Собственно,начал подзабывать язык,решил возродить. Есть задача. Даны 2 текстовых файла с произвольной информацией внутри,произвести обмен информацией,что бы в первом была инфа второго,во втором- первого.Использовать ренейм нельзя.Собственно идея такая,завести 3 файл и через него, как буфер(аналогично обмену 2 переменных).Собсвенно интересует,есть ли вобможность незаводя 3 файла сделать такую операцию? И еще Readblock и wrihteblock смогут отработать с sizeof(file)?
IUnknown
25.05.2011 3:13
Цитата
Даны 2 текстовых файла с произвольной информацией внутри
Ну, текстовые-то они, если откроешь их как текстовые. Их ведь можно открыть и как file of byte, и как file of char... И как бестиповый в конце концов...
Цитата
Собсвенно интересует,есть ли вобможность незаводя 3 файла сделать такую операцию?
Собственно, почему бы и нет?
Ку?(Показать/Скрыть)
type
item = char;
ftype = fileof item;
function read_file(var f : ftype) : item;
var buf : item;
begin
read(f, buf);
seek(f, filepos(f) - sizeof(item));
read_file := buf;
end;
procedure write_file(var f : ftype; buf : item);
begin
write(f, buf);
end;
var
f, g : ftype;
b : item;
posf, posg : longint;
begin
assign(f, '01.txt'); reset(f);
posf := filesize(f);
assign(g, '02.txt'); reset(g);
posg := filesize(g);
eoff := false; eofg := false;
whilenot eof(f) andnot eof(g) dobegin
b := read_file(f);
write_file(f, read_file(g));
write_file(g, b);
end;
if eof(f) thenwhilenot eof(g) dobegin
read(g, b);
write(f, b);
end;
if eof(g) thenwhilenot eof(f) dobegin
read(f, b);
write(g, b);
end;
seek(f, posg); truncate(f);
seek(g, posf); truncate(g);
close(f); close(g);
end.
Цитата
И еще Readblock и wrihteblock смогут отработать с sizeof(file)?
sizeof(file) - это размер записи, представляющей информацию о файле, а не размер самого файла. Для получения размера файла - FileSize(f)... А Read/Writeblock работают с буфером. Какой выделишь - с тем и будут работать.
Как я понимаю идея такова,что происходит чтение и запись в начало файла,а потом транкейтом отрезается все,что после позиции, указывающей на конец другого файла?Интересненько. Еще 2 таких вопроса. seek(f, filepos(f) - sizeof(item)); это мы как раз и втыкаем наш символ перед первым символом в файле? И зачем нужна процеруда write_file,разве мы не можем write_file(f, read_file(g)); сделать с обычным write?
IUnknown
25.05.2011 20:07
Цитата
Как я понимаю идея такова,что происходит чтение и запись в начало файла,а потом транкейтом отрезается все,что после позиции, указывающей на конец другого файла?
Да, если этого не сделать - то более короткий файл перезапишется данными из более длинного, тут все будет в порядке. А вот тот, что был длиннее - будет хранить "хвост" из своих старых данных. Его надо убрать. В принципе, нужен только один Truncate - для более длинного изначально файла.
Цитата
seek(f, filepos(f) - sizeof(item)); это мы как раз и втыкаем наш символ перед первым символом в файле?
Это мы после того, как прочли из файла очередную порцию данных (если интересно - покажу, как сделать это же самое с бестиповым файлом, там можно вычислить наибольший общий делитель размеров, для того, чтобы минимизировать число операций чтения/записи, не всегда читать побайтно), возвращается назад, чтоб потом ТУДА ЖЕ, откуда прочли, записать данные, считанные с другого файла.
Цитата
И зачем нужна процеруда write_file,разве мы не можем write_file(f, read_file(g)); сделать с обычным write?
Можем. Но выглядит лучше - когда процедуры "парные". blockread/blockwrite, read/write, readln/writeln... И тут я буду использовать read_file/write? Нет, не буду.
Krjuger
25.05.2011 20:22
Все теперь кажись окончательно понял,мы скидываем в буфер "порцию",затем затираем в исходном файле эту порцию порцией из другого файла и в другой записываем то,что из буфера.
Цитата
если интересно - покажу, как сделать это же самое с бестиповым файлом, там можно вычислить наибольший общий делитель размеров, для того, чтобы минимизировать число операций чтения/записи, не всегда читать побайтно
Ну это уже принципи более менее понятно,т.к "порция" это абстрактная вещ.В текущем случае это char,а в бестипном, найдя НОД, будет nное кол-во байтов.
IUnknown
25.05.2011 20:27
Цитата
Ну это уже принципи более менее понятно
Хорошо... Понятно, говоришь? Можно попросить тебя реализовать тот же самый алгоритм, но используя именно бестиповые файлы + НОД для того, чтобы (возможно) не читать байт за байтом, а читать максимально возможными порциями?
TarasBer
25.05.2011 21:00
Зачем НОД? Почему мы берём именно фиксированный размер считываемой порции? Да можно сразу взять буфер на 64 килобайта и через него делать, а если после очередной считки буфер заполнился не до конца, то так и запомнить.
IUnknown
25.05.2011 21:19
Цитата
Зачем НОД? Почему мы берём именно фиксированный размер считываемой порции? Да можно сразу взять буфер на 64 килобайта и через него делать
Потому что МНЕ так хочется. Такой ответ устроит? Память - не резиновая, у меня НЕТ свободных 64К, чтобы прочесть в них 800 байт из файла.
Вот когда ты будешь писать - будешь делать так, как захочется тебе. Идея понятна?
Krjuger
25.05.2011 22:05
Ну чтож я попытался,но не все так прекрасно вышло))))Мне почти удалось переписаль содержимое файлов друг в дружку за исключением пары ньюансов
Хотя не, вру,еще чуть чуть и будет более менее пристойный вариант.
В общем оно вроде работает
function nod(x,y : longint):longint;
beginif x<>0then nod:=nod( y mod x, x) else nod:=y;
end;
var
f, g :file;
b,p : string;
posf, posg :longint;
ser: longint;
begin
assign(f, '01.txt'); reset(f,sizeof(byte));
posf :=filesize(f);
assign(g, '02.txt'); reset(g,sizeof(byte));
posg :=filesize(g);
ser:=nod(posf,posg);
whilenot eof(f) andnot eof(g) dobegin
BlockRead(f,b,Sizeof(byte)*ser);
seek(f,filepos(f)-Sizeof(byte)*ser);
BlockRead(g,p,Sizeof(byte)*ser);
seek(g,filepos(g)-Sizeof(byte)*ser);
BlockWrite(f,p,Sizeof(byte)*ser);
BlockWrite(g, b,Sizeof(byte)*ser);
end;
if eof(f) thenwhilenot eof(g) dobegin
BlockRead(g,b,sizeof(byte));
Blockwrite(f, b,sizeof(byte));
end;
if eof(g) thenwhilenot eof(f) dobegin
BlockRead(f, b,sizeof(byte));
BlockWrite(g, b,sizeof(byte));
end;
seek(f,posg); truncate(f);
seek(g,posf); truncate(g);
close(f); close(g);
end.
Не пинайте сильно,принципи можно было бы как то и свести к тому,что мне показывали,но как передать чтобы функция возвращала нужную мне длинну я хз)))реч о read_file : item;
P.S.Несмотря на то,что последняя строчка вне тегов кода,у меня почему то отображается внутри.
Не делай так больше никогда. Ибо если размеры файлов будут кратны, друг другу, скажем, первый = 1010 байт, второй - 2020, то получишь "биг бада бум" (С) при попытке считать в строку (с максимальной длиной 255 символов) те же 1010 байт. Буфер надо выделять динамически. Кстати, когда будешь это делать - подумай над тем, что будет, если размер первого файла = 74184 байта, а второго - 222552 байт. Вот когда твоя программа будет отрабатывать и на таких файлах - тогда будем говорить дальше Ты сам сказал, что
Цитата
Даны 2 текстовых файла с произвольной информацией внутри
, стало быть, размер файлов может быть тоже произвольным...
TarasBer
26.05.2011 13:18
> Память - не резиновая, у меня НЕТ свободных 64К, чтобы прочесть в них 800 байт из файла.
64K - для примера. Можно и 4K, или любое удобное число. Поиск числа, на которое делится размер файла, не имеет никакого смысла, кроме как для учебной задачи.
> Потому что МНЕ так хочется. Такой ответ устроит?
Типа как доп.задание? Ну ладно... Главное понимать, что это всего лишь учебное задание, а реального смысла в этом нет.
Krjuger
26.05.2011 16:34
Цитата
Вот когда твоя программа будет отрабатывать и на таких файлах - тогда будем говорить дальше
А может лучше не надо дальше?))) Я конешно постараюсь,что что то интузиазм угасает уже)
Цитата
Буфер надо выделять динамически
А тогда по какому принципу записывать в буфер информацию?Например у нас есть.
type
PerconPointer = ^PerconRecord;
PerconRecord = record
temp: string;
Next: PerconPointer
end;
В каждое поле записывать по 255 символов,либо temp будет чаром,но тогда мы недалеко уйдем от считывания по 1 байту.Получается что хоть у нас буфер и будет каким мы заходим,но его заполнение у меня упрется все равно в теже самые 255 символов,более того,если нельзя переписать сразу весь буфер(в данном случае я не знаю можно ли или нет) то наши труды будут весьма сомнительны.В общем то нужен вброс какой то информации,мои знания немного заканчиваются.
P.S.Если вспомнить откуда я брал задачку (методичка для 1 курса) то там решением задачи был бы самый первый код,дальше люди просто не проходили)
TarasBer
26.05.2011 17:13
Динамический буфер делается не так. Заводишь тип-указатель на массив максимально возможной длины (65534 байта), выделяешь для него нужное кол-во памяти через GetMem, потом, поработав с ним, освобождаешь через FreeMem
Я думал, у тебя ТурбоПас. Если у тебя Дельфи, то да, примерно так. Только SetLength(Buf, FSize) - это немного опрометчиво, файлы и на два гига бывают.
IUnknown
26.05.2011 18:42
Цитата
Заводишь тип-указатель на массив максимально возможной длины (65534 байта), выделяешь для него нужное кол-во памяти через GetMem, потом, поработав с ним, освобождаешь через FreeMem
лучше не превышать 65528:
Цитата(GetMem function)
Restrictions: The largest block that can be safely allocated on the heap at one time is 65,528 bytes (64K-$8).
Если у кого-то и где-то один раз получилось выделить все 65534 - он может считать, что ему повезло. Гарантированно выделяется не больше 65528, все остальное зависит от фазы Луны и разных других факторов. В любом случае, для написания надежной программы не стоит обходить то, что написано в документации. Даже если очень хочется... Но на эту темя я уже говорил, повторяться не буду. Хотите обходить правила - обходите. Потом - не жалуйтесь!!!
TarasBer
26.05.2011 18:49
Хорошо, пусть будет 65528. Параметры типа ни на что всё равно не влияют в данном случае.
Krjuger
26.05.2011 19:43
Цитата
думал, у тебя ТурбоПас. Если у тебя Дельфи, то да, примерно так.
У меня и то и то есть,но как сделать на турбо я вообще не знаю...Хотя сделать надо именно на турбо(
TarasBer
26.05.2011 19:47
Я же объяснил всё.
type
TBigArr = array [0 .. 65528] of byte;
PBigArr = ^TBigArr;
var
Buf: PBigArr;
...
GetMem(Buf, сколько надо);
...
работаем
...
FreeMem(Buf, сколько было надо, надо освободить ровно столько, сколько и заняли);
Krjuger
26.05.2011 21:32
Что я делаю не так.
type
TArr= array [0..65528] of byte;
PArr = ^TArr;
function nod(x,y : longint):longint;
beginif x<>0then nod:=nod( y mod x, x) else nod:=y;
end;
var
f, g :file;
b,p : PArr;
posf, posg :longint;
ser: longint;
begin
assign(f, '01.txt'); reset(f,Sizeof(byte));
posf :=filesize(f);
assign(g, '02.txt'); reset(g,Sizeof(byte));
posg :=filesize(g);
ser:=nod(posf,posg);
whilenot eof(f) andnot eof(g) dobegin
GetMem(b,ser);
GetMem(p,ser);
BlockRead(f,b,ser);
seek(f,filepos(f)-Sizeof(byte)*ser);
BlockRead(g,p,ser);
seek(g,filepos(g)-Sizeof(byte)*ser);
BlockWrite(f,p,ser);
BlockWrite(g,b,ser);
FreeMem(b,ser);
FreeMem(p,ser);
end;
GetMem(b,ser);
GetMem(p,ser);
if eof(f) thenwhilenot eof(g) dobegin
BlockRead(g,b,sizeof(byte));
Blockwrite(f, b,sizeof(byte));
end;
if eof(g) thenwhilenot eof(f) dobegin
BlockRead(f, b,sizeof(byte));
BlockWrite(g, b,sizeof(byte));
end;
seek(f,posg); truncate(f);
seek(g,posf); truncate(g);
dispose(b);
dispose(p);
close(f); close(g);
end.
На строчке FreeMem(b,ser); Invalid pointer operation.
IUnknown
26.05.2011 22:01
Цитата
Что я делаю не так.
Хм... Как бы, не надо читать данные туда, где находится сам указатель. Надо читать туда, куда он указывает:
BlockRead(f,b^,ser);
Ты же читал прямо в указатель (и в смежные с ним переменные), разумеется все портил к чертям собачьим, а потом еще и вызывал FreeMem неизвестно какой области (кто знает, что там было в файле, и куда теперь указывают b и p). Еще скажи спасибо, что получаешь "Invalid pointer operation", могло бы по-тихому что-то там освободить, и ты б не узнал, что делаешь что-то не так...
P.S. С записью через BlockWrite - та же петрушка: передавай ей сам буфер, т.е., разыменованный указатель. Да, а кто будет освобождать память после окончательного завершения копирования?
Krjuger
26.05.2011 23:15
Я пробовал мнооого вариантов в одном из них мой файлик освободился так,что туда 930 мегабайт записалось)))Лан щас дорвусь до компа попробую.
BlockRead(f,b^,ser);
Нечто подолное я видел,но там была связка вида
var
b : ^byte;\\Ну или ^integer, ^real и тд
...........
BlockRead(f,b^,ser);
Krjuger
26.05.2011 23:45
Так,я совсем запутался.У меня есть b и p ,указатели на массивы байтов,выделить мне память надо для самих массивов так?Если да,то проведя анолонию с предыдущими комметариями я должен вызвать GetMem от разименованного указателя GetMem(b^,ser); Но сделав это я при компиляции получаю .Poiter variable expected.
IUnknown
27.05.2011 0:05
Цитата
Если да,то проведя анолонию с предыдущими комметариями я должен вызвать GetMem от разименованного указателя GetMem(b^,ser);
Нет... Погоди, ты меня тоже запутал...
Значит, так: выделяешь память, адрес выделенного блока заносишь в указатель (а не туда, куда он указывает. Он у тебя еще не указывает никуда):
GetMem(b, ser); // Без разыменования
// работаешь - БУФЕРОМ, на который УКАЗЫВАЕТ b:
BlockRead(f, b^, ser); // С разыменованием
BlockWrite(f, b^, ser); // аналогично...
// освобождаешь - память, адрес которой хранится в УКАЗАТЕЛЕ:
FreeMem(b^, ser);
Откуда ты взял, что надо в GetMem/FreeMem разыменовывать указатель? Эти процедуры выделяют память, а не работают с ней, поэтому имеют дело только с самим указателем. Куда он указывает - их мало интересует (если вообще интересует).
У тебя F1 заело? Посмотри, что пишет контекстная помощь о GetMem/FreeMem и что - о BlockRead/BlockWrite:
procedure BlockRead(var F: File; var Buf; Count: Word [; var Result: Word]); procedure BlockWrite(var f: File; var Buf; Count: Word [; var Result: Word]);
Чувствуешь разницу? Гте-то нужен указатель, а где-то - бестиповый кусок памяти. Это - как раз то, на что указатель показывает...
Krjuger
27.05.2011 0:50
У меня "семерка" 64 разрядная,так что запускаю я через Dos box, навыков работы с ним у меня мало(практически нет) все что могу это запустить ту программу,что мне нужна.В общем вместо хелпа он мне выдает кучу всяких иероглифоф в которых разобратсья невозможно,понятно,что надо менять кодировку,но где и как, я не знаю.Когда я пытался запускать ЛИСП он вообще отказывался подключать хелп и говорил,что его нету.
В общем исправил,нормально отработало с файлами на 1 КБ и 84 КБ.Но что то мне кажется,что если оба файла будут больше и их кратность будет больше чем 64кб,то тут возникнут проблемы. Кстати время выполнения уже становится физически ощутимым.(возможно из-за эмулятора).
type
TArr= array [0..65528] of byte;
PArr = ^TArr;
function nod(x,y : longint):longint;
beginif x<>0then nod:=nod( y mod x, x) else nod:=y;
end;
var
f, g :file;
b,p : PArr;
posf, posg :longint;
ser: longint;
begin
assign(f, '01.txt'); reset(f,Sizeof(byte));
posf :=filesize(f);
assign(g, '02.txt'); reset(g,Sizeof(byte));
posg :=filesize(g);
ser:=nod(posf,posg);
GetMem(b,ser );
GetMem(p,ser);
whilenot eof(f) andnot eof(g) dobegin
BlockRead(f,b^,ser);
seek(f,filepos(f)-Sizeof(byte)*ser);
BlockRead(g,p^,ser);
seek(g,filepos(g)-Sizeof(byte)*ser);
BlockWrite(f,p^,ser);
BlockWrite(g,b^,ser);
end;
if eof(f) thenwhilenot eof(g) dobegin
BlockRead(g,b^,ser);
Blockwrite(f, b^,ser);
end;
if eof(g) thenwhilenot eof(f) dobegin
BlockRead(f, b^,ser);
BlockWrite(g, b^,ser);
end;
seek(f,posg); truncate(f);
seek(g,posf); truncate(g);
FreeMem(b,ser);
FreeMem(p,ser);
close(f); close(g);
end.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.