Форум » [x]Harbour » FOPEN() -> FWRITE() -> FCLOSE() » Ответить

FOPEN() -> FWRITE() -> FCLOSE()

Sergy: Добрый день Есть у меня стандартный алгоритм, который открывает файл на запись и кусочками через FWRITE() с красивым прогресс-баром записывает его, после чего закрывает. Столкнулся с тем, что при записи на USB флэшки и/или некоторые ресурсы с медленным доступом прогресс почти мгновенно добегает до 100%, после чего доооолго висит на отработке команды FCLOSE(). Понятное дело, что это кэш Windows. Как-бы пофиксить такое поведение ? То есть нужна какая-то команда после FWRITE(), (по аналогии с базой данных - DBCOMMIT()) которая дожидалась бы окончания процесса физической записи на носитель, после чего брался-бы следующий кусок и тд.

Ответов - 12 новых

Dima: Попробуй вместо FOPEN() -> FWRITE() -> FCLOSE() HB_VFOPEN() -> HB_VFWRITE() -> HB_VFCLOSE() Возможно результат будет иным.

SergKis: Делаю добавку к max счетчику ~ 1/3 - 1/5 от значения для индикации, т.е. не довожу до конца бегунка весь процесс копирования (один файл или несколько их или расчета по алгоритмам) и потом, выйдя из цикла (можно подержать паузу тут из ini), довожу бегунок до конца с интервалом от 0.1 - 0.7 сек. (по умолчанию 0.5). Потом вывожу текст о завершении или статистика и подвешиваю ~3-5 сек.

Dima: Sergy пишет: с красивым прогресс-баром Покажи картинку


Pasha: Наблюдал подобное при копировании файлов фаром на флешку. У него свой прогресс-бар. Может быть такой эффект дает антивирус

Dima: Pasha пишет: Наблюдал подобное при копировании файлов фаром на флешку Тоже происходит и при копировании файлов на USB винт.

SergKis: SergKis пишет Делаю добавку к max счетчику ~ ... Другой вариант для бегунка исп. таймер (при достижении max, начинать с начала счетчик бегунка, если надо). В функцию такого бегунка передаю блок кода, счетчик max, шаг и заголовок окна. Ф-я не большая (МиниГуи), как есть, чисто для инфы [pre2] *-----------------------------------------------------------------------------* FUNCTION Do_WaitWindow( bBlk, nMax, nStep, cCapt ) *-----------------------------------------------------------------------------* LOCAL nY := GetBorderHeight() LOCAL nX := GetBorderWidth() LOCAL nH := 60, nTime := 1000 //, lClose := .F. LOCAL hWnd, aHmg, lBlk := HB_ISBLOCK(bBlk) LOCAL y := 0, x := 0, w := 320, h := nH PRIV lClose := .F. DEFAULT bBlk := {|| Nil }, ; nStep := 10, ; nMax := 250, ; cCapt := gTxt(Wait) hWnd := iif( _HMG_BeginWindowMDIActive, GetActiveMdiHandle(), GetActiveWindow() ) aHmg := Save_Rest_HMG(hWnd) DEFINE WINDOW wWait ; AT y, x ; WIDTH w + nX * 2 ; HEIGHT h + nY * 2 + GetTitleHeight() ; TITLE cCapt ; MODAL NOSIZE NOSYSMENU ; ON INIT ( SetWaitCursor( App.Handle ), ; SetWaitCursor( This.ProgressBar.Handle ), ; CursorWait(), oWin:PostMsg(1), ; This.tWait.Enabled := .T., DoEvents(), ; Eval(bBlk, oWin), ; oWin:PostMsg(2), DoEvents() ) ; ON RELEASE ( This.tWait.Enabled := .F., ; This.ProgressBar.Value := oWin:Cargo[3], ; InkeyGui(500), ; SetArrowCursor( This.ProgressBar.Handle ), ; SetArrowCursor( App.Handle ), ; CursorArrow(), InkeyGui(100), ; Save_Rest_HMG(aHmg) ) ; ON INTERACTIVECLOSE lClose PRIV oWin := ThisWindow.Object oWin:Cargo := { nStep, 0, nMax } oWin:Event( 1, {|ow,nk| nk := ow:Cargo[2] + ow:Cargo[1], ; ow:Cargo[2] := iif( nk > ow:Cargo[3], 0, nk ), ; wWait.ProgressBar.Value := ow:Cargo[2], ; iif( ow:Cargo[2] == 0, ow:PostMsg(1), ), ; wWait.tWait.Enabled := .T., DoEvents() } ) oWin:Event( 2, {|| lClose := .T., wWait.Release } ) oWin:Event( 3, {|| wWait.tWait.Enabled := .F., DoEvents() } ) oWin:Event( 4, {|| wWait.tWait.Enabled := .T., DoEvents() } ) @ y, x PROGRESSBAR ProgressBar RANGE 0, nMax ; WIDTH ThisWindow.ClientWidth ; HEIGHT ThisWindow.ClientHeight DEFINE TIMER tWait INTERVAL nTime ACTION ( wWait.tWait.Enabled := .F., oWin:PostMsg(1) ) This.tWait.Enabled := .F. y := App.Row + int((App.Height - h) / 2) x := App.Col + int((App.Width - w) / 2) h += nY MoveWindow( oWin:Handle, x, y, w, h ) END WINDOW ACTIVATE WINDOW wWait Save_Rest_HMG(aHmg) RETURN NIL [/pre2]

Sergy: Dima пишет: Покажи картинку Вот так работает у меня hb_ZipFile(): Тут два прогресса: общий, по всем файлам плюс внутри каждого файла. А вот при копировании архива на съемный носитель получается сразу 100% и потом FCLOSE(). Пойду почитаю про hb_vfFWrite(). Потому как шаманства со счетчиком не очень идея, тк сложно угадать реальное время записи - на флэшке одна скорость, на удаленном бэкап сервере под своей нативной ОС (там что-то типа TrueNAS OS) - своя скорость. При копировании даже внутри локальной сети - третья скорость... Плюс целый зоопарк машин с разной производительностью, плюс разная загрузка сети в зависимости от числа активных юзеров...

Sergy: Pasha пишет: Наблюдал подобное при копировании файлов фаром на флешку. У него свой прогресс-бар. Может быть такой эффект дает антивирус Вот как раз Far копирует так, как нужно, прогресс движется достаточно равномерно и при достижении 100% копирование полностью завершено: если тут-же нажать на иконку "безопасного извлечения" - все ок.

SergKis: Sergy пишет Пойду почитаю про hb_vfFWrite() Если поможет, хорошо, и если в ней есть упр. буф. windows Потому как шаманства со счетчиком не очень идея, тк сложно угадать реальное время записи Если сохранить (при первом копировании или при каждом) для файла[ов] время записи (для устройства от fOpen() до fClose()) в ini (раб. месте) для конкретной PC, то потом можно ставить (с коэффициентом) это время, например в схему выше по таймеру и уже, думаю, будешь попадать в "струю" как надо. PS hbedit редактор имеет файл открытий файлов с запоминанием CDP и ..., ставлю у себя в ini 1500 строк для этого журнала работает как часы PS2 Переписав на устройство, например, тестовый файл (в скрытом режиме) и удалив его потом, можно опр условную единицу для расчета счетчика и шага и исп. это значение исходя из длины файлов + коэффициент увеличения, сохранить это значение и исп. его для работы с этим устройством. Тоже вариант "бегунка" по таймеру

Sergy: Итак Связка hb_vfOpen() -> hb_vfWrite() -> hb_vfClose() ЗАРАБОТАЛА в нужном ключе. Потому что есть волшебный hb_vfCommit() Единственное, что пришлось повозиться с hb_vfOpen(), тк при использовании его вместо FCREATE() нужно указывать атрибуты FO_CREAT+FO_TRUNC+FO_WRITE. Я сначала поставил только первый, получил os error - 5 - Access denied и созданный выходной файл нулевого размера. Часа полтора прыгал, не мог понять, где косяк - как так - файл создать можно, а записать в него нельзя. И нужно поиграть размером буфера. Был у меня по умолчанию 16Кб, он сильно замедляет процесс. Поставил размером 5% от MEMORY( HB_MEM_BLOCK ) - получился 100 мегабайт буфер, прогресс на медленных носителях выходит "рывками". Остановился на подходящем - 512Kb. С ним все норм. Спасибо за помощь, друзья. PS: вирусы шифровальщики - зло. Делайте бэкапы регулярно пожалуйста.

Pasha: Sergy пишет: Потому что есть волшебный hb_vfCommit() Оказывается, есть и hb_FCommit, который можно использовать с FOpen/FWrite

Sergy: Pasha пишет: Оказывается, есть и hb_FCommit, который можно использовать с FOpen/FWrite Ваще крутяк Посмотрел, как он реализован: [pre2]HB_FUNC( HB_FCOMMIT ) { HB_ERRCODE uiError = 6; if( HB_ISNUM( 1 ) ) { hb_fsCommit( hb_numToHandle( hb_parnint( 1 ) ) ); uiError = hb_fsError(); } hb_fsSetFError( uiError ); } [/pre2]



полная версия страницы