![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Алгоритм деления файла на фрагменты. [D7, WinXP]
Фёдор Мегатронов © (2005-01-10 02:42:00)Вобщем мне надо один файл поделить на заданное колличество кусков и затем их записать в один.
Если с сборкой кусков в исходный файл никаких проблем, то вот с ПРАВИЛЬНЫМ делением исходного файла- одни проблемы.
Мой алгоритм
{размер всех кусков кроме последнего}
размер куска := размер файла div на кол-во кусков
затем я считываю из файла по байту в буффер и записываю их в другой файл до тех пор пока он не станет равер размеру куска.
далее указатель устанавливаеться на исходный файл на размер куска + 1 и опять считывается в буффер до тех пор пока он не будет равен куску файла и затем записываеться в новый файл - второй кусок.
Вобщем штука такая, что почему-то в куски записываеться не то колличество байт которое нужно. И сложно сказать правильный ли размер имеет первый кусок и последний.
Не могли бы вы подсказать какой-нибудь алгоритм разбиения файла на куски с дальшейшим их соединением обратно в рабочий файл ?
jack128 (2005-01-10 04:54:00) [1]Открытие/закрытие файла в инете, проверка Terminated, обработка исключений - это все на твой совести.
jack128 (2005-01-10 04:52:00) [2]Вот примерно такой процедуркой ты можешь скачать часть файла
const
// размер части, на которую мы делим наш файл
FileSize = 64* 1024;
// скачиваем файл из инета по 1024 байта
BufSize = 1024;
var
fExists: boolean;
f: file;
TotalToRead, TotalReaded: Integer;
ToRead, Readed: Integer;
UrlFileSize: Integer;
begin
// PartNo - этот номер скачивамой части, начиная с 1
FileName := 'part' + IntToStr(PartNo) + '.part';
AssignFile(f, FileName);
fExists := FileExists(FileName);
// Открываем файл на диске
if fExists then
reset(f, 1)
else
Rewrite(f, 1);
try
FPos := FileSize * (PartNo - 1) + System.FileSize(f);
InternetSetFilePointer(UrlFile, FPos);
// Определяем сколько данных нам нужно скачать
if fExists then
TotalToRead := FileSize - System.FileSize(f);
else
TotalToRead := FileSize;
// Что бы не вылезать за границу файла
TotalToRead := Min(InternetGetFileSize(UrlFile) - FPos, TotalToRead); // незнаю существует ли такая функция, если нет, то сам ж напиши, я в сетях не силен..
TotalReaded := 0;
// Выделяем буффер
SetLength(Buffer, BuffSize);
while (TotalReaded < TotalToRead) do
begin
ToRead := Min(BufSize, TotalToRead - TotalReaded);
if not InternetReadFile(UrlFile, PChar(Buffer)^, ToRead, Readed) or (ToRead < Readed) then
raise Exception.Create('Reading error');
inc(TotalReaded, Readed);
end;
finally
CloseFile(f);
end;
end;
Фёдор Мегатронов (2005-01-10 03:58:00) [3]на счёт условия
UNTIL ((FileSize(F) = FPartSize) может и не быть если (FPartSize mod irfBytesToRead ) <> 0 ... тоесть условие сработает только если >= или <= .. но вероятность того что оно будет = - 0,000001 процент...
если это условие не выполняеться, то гда первый кусок будет размером с весь исходный файл, а не с кусок.
поэтому я насильно размер считываемого буфера подгоняю так чтобы он делил без остатка.
эти 1024 там взялись потому что я уже просто незнаю почему ничего не работает ... и начал туда всё подряд припысывать.
там было и +1 и -1 и ещё черти чего 8).
Один раз я даже добился правильного размера файла ! но файл всёравно получался нерабочий.
jack128 (2005-01-10 03:45:00) [4]
>case Form2.Part of
>
> 1:
> begin
> FPos := 0;
> end;
>
> 2:
> begin
> FPos := FPartSize + 1024;
> end;
>
> 3:
> begin
> FPos := FPartSize * 2 + 1024;
> end;
>
> 4:
> begin
> FPos := FPartSize * 3 + 1024;
> end;
>
> 5:
> begin
> FPos := FPartSize * 4 + 1024;
> end;
>
> end; {of case}
мда..
if Form2.Part = 1 then
FPos := 0
else
FPos := FPartSize * (Form2.Part - 1) + 1024;
Фёдор Мегатронов (10.01.05 3:07) [2]
{этот ИФ нужен для того чтобы выполнилось условие в цикле REPEAT}
If (FPartSize mod irfBytesToRead ) <> 0
then
begin
Repeat
Inc(irfBytesToRead);
Until (FPartSize mod irfBytesToRead) = 0
end;
А каким образом irfBytesToRead влияет на услови в until??
А вообще, что тот у тебя с логикой в программе нето.. Откуда 1024 взялось?? Что это такое??
Фёдор Мегатронов (2005-01-10 03:07:00) [5]Вот куски кода отвечающие за деление файла (файл делиться условно, т.к. он в инете)
FPartSize := FSizeBytes div Form2.Parts;
{этот ИФ нужен для того чтобы выполнилось условие в цикле REPEAT}
If (FPartSize mod irfBytesToRead ) <> 0
then
begin
Repeat
Inc(irfBytesToRead);
Until (FPartSize mod irfBytesToRead) = 0
end;
{ Открываем файл на винче }
if FileExists(Form2.FileDir + IntToStr(Form2.Part) + '_partof_' + Form2.FileName)
then
begin
AssignFile(F, Form2.FileDir + IntToStr(Form2.Part) + '_partof_' + Form2.FileName);
Reset(F, 1);
FPos := FileSize(F);
Seek(F, FileSize(F));
end
else
try
AssignFile(F, Form2.FileDir + (IntToStr(Form2.Part) + '_partof_' + Form2.FileName));
Rewrite(F, 1);
except
Application.MessageBox('Недопустимые символы в имени файла!','Ошибка!');
Exit;
end;
{ Проверяем файл на возможность докачки }
if FPos > 0
then
begin
InternetSetFilePointer(hURL, FPos, nil, 0, 0);
end
else
begin
case Form2.Part of
1:
begin
FPos := 0;
end;
2:
begin
FPos := FPartSize + 1024;
end;
3:
begin
FPos := FPartSize * 2 + 1024;
end;
4:
begin
FPos := FPartSize * 3 + 1024;
end;
5:
begin
FPos := FPartSize * 4 + 1024;
end;
end; {of case}
InternetSetFilePointer(hURL, FPos, nil, 0, 0);
end;
{ Создаём буфер для считывания }
GetMem(irfBuffer, irfBytesToRead);
{ Запускаем основной цикл скачивания }
REPEAT
{ проверка на завершение потока }
If Terminated
then
begin
Application.MessageBox('Процесс прерван. Всё что было скачано - сохранено. Чтобы продолжить закачку позже - просто начните скачивать этот-же файл','Процесс прерван');
InternetCloseHandle(hSession);
InternetCloseHandle(hUrl);
CloseFile(F);
Synchronize(RefreshOnStop);
Exit;
end;
{ Проверка на кол-во реально прочитанных байт }
NoError := InternetReadFile(hURL, irfBuffer, irfBytesToRead, irfBytesReaded);
{ Если они равны нулю, то ничего не качаем}
if NoError = false
then
begin
Application.MessageBox('Неправельно указан адрес файла, либо он отсутствует на сервере', 'Ошибка!');
InternetCloseHandle(hSession);
InternetCloseHandle(hUrl);
CloseFile(F);
FreeMem(irfBuffer, irfBytesToRead);
Synchronize(RefreshOnStop);
Exit;
end
else
begin
BlockWrite(F, irfBuffer^, irfBytesReaded);
{ Прогресс }
Synchronize(RefreshGauge);
Synchronize(RefreshBytesToGo);
end;
{ Пока будет что читать }
UNTIL ((FileSize(F) = FPartSize) and (Form2.Parts <> Form2.Part)) or (irfBytesReaded = 0);
в конце концов файл на КБ больше исходного.
У меня там было много комбинаций в CASE .. и отнимал там 1024 и прибавлял 1 ... и чего только не далал методом тыка 8) ..
потому что так ка кджолжно почему-то не работает 8)
чисто теоретически всё верно
jack128 (2005-01-10 02:55:00) [6]Давай, показывай, что ты наваял :-) Нахаляву готовый код получить не удасться ;-)