Помощь - Поиск - Пользователи - Календарь
Полная версия: Обмен информацией в файлах.
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
Krjuger
Собственно,начал подзабывать язык,решил возродить.
Есть задача.
Даны 2 текстовых файла с произвольной информацией внутри,произвести обмен информацией,что бы в первом была инфа второго,во втором- первого.Использовать ренейм нельзя.Собственно идея такая,завести 3 файл и через него, как буфер(аналогично обмену 2 переменных).Собсвенно интересует,есть ли вобможность незаводя 3 файла сделать такую операцию?
И еще Readblock и wrihteblock смогут отработать с sizeof(file)?
IUnknown
Цитата
Даны 2 текстовых файла с произвольной информацией внутри
Ну, текстовые-то они, если откроешь их как текстовые. Их ведь можно открыть и как file of byte, и как file of char... И как бестиповый в конце концов...

Цитата
Собсвенно интересует,есть ли вобможность незаводя 3 файла сделать такую операцию?
Собственно, почему бы и нет?

Ку? (Показать/Скрыть)


Цитата
И еще Readblock и wrihteblock смогут отработать с sizeof(file)?
sizeof(file) - это размер записи, представляющей информацию о файле, а не размер самого файла. Для получения размера файла - FileSize(f)... А Read/Writeblock работают с буфером. Какой выделишь - с тем и будут работать.
Krjuger

seek(f, posg); truncate(f);
seek(g, posf); truncate(g);


Как я понимаю идея такова,что происходит чтение и запись в начало файла,а потом транкейтом отрезается все,что после позиции, указывающей на конец другого файла?Интересненько.
Еще 2 таких вопроса.
seek(f, filepos(f) - sizeof(item));
это мы как раз и втыкаем наш символ перед первым символом в файле?
И зачем нужна процеруда write_file,разве мы не можем write_file(f, read_file(g)); сделать с обычным write?
IUnknown
Цитата
Как я понимаю идея такова,что происходит чтение и запись в начало файла,а потом транкейтом отрезается все,что после позиции, указывающей на конец другого файла?
Да, если этого не сделать - то более короткий файл перезапишется данными из более длинного, тут все будет в порядке. А вот тот, что был длиннее - будет хранить "хвост" из своих старых данных. Его надо убрать. В принципе, нужен только один 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
Все теперь кажись окончательно понял,мы скидываем в буфер "порцию",затем затираем в исходном файле эту порцию порцией из другого файла и в другой записываем то,что из буфера.
Цитата

если интересно - покажу, как сделать это же самое с бестиповым файлом, там можно вычислить наибольший общий делитель размеров, для того, чтобы минимизировать число операций чтения/записи, не всегда читать побайтно

Ну это уже принципи более менее понятно,т.к "порция" это абстрактная вещ.В текущем случае это char,а в бестипном, найдя НОД, будет nное кол-во байтов.
IUnknown
Цитата
Ну это уже принципи более менее понятно
Хорошо... Понятно, говоришь? smile.gif Можно попросить тебя реализовать тот же самый алгоритм, но используя именно бестиповые файлы + НОД для того, чтобы (возможно) не читать байт за байтом, а читать максимально возможными порциями?
TarasBer
Зачем НОД? Почему мы берём именно фиксированный размер считываемой порции? Да можно сразу взять буфер на 64 килобайта и через него делать, а если после очередной считки буфер заполнился не до конца, то так и запомнить.
IUnknown
Цитата
Зачем НОД? Почему мы берём именно фиксированный размер считываемой порции? Да можно сразу взять буфер на 64 килобайта и через него делать
Потому что МНЕ так хочется. Такой ответ устроит? Память - не резиновая, у меня НЕТ свободных 64К, чтобы прочесть в них 800 байт из файла.

Вот когда ты будешь писать - будешь делать так, как захочется тебе. Идея понятна?
Krjuger
Ну чтож я попытался,но не все так прекрасно вышло))))Мне почти удалось переписаль содержимое файлов друг в дружку за исключением пары ньюансов mad.gif

Хотя не, вру,еще чуть чуть и будет более менее пристойный вариант.

В общем оно вроде работает smile.gif

function nod(x,y : longint):longint;
begin
if x<>0 then 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);

while not eof(f) and not eof(g) do
begin
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) then
while not eof(g) do
begin
BlockRead(g,b,sizeof(byte));
Blockwrite(f, b,sizeof(byte));
end;
if eof(g) then
while not eof(f) do
begin
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.Несмотря на то,что последняя строчка вне тегов кода,у меня почему то отображается внутри.
IUnknown
Цитата
  b,p : string;
// ...
BlockRead(f,b,Sizeof(byte)*ser);
Не делай так больше никогда. Ибо если размеры файлов будут кратны, друг другу, скажем, первый = 1010 байт, второй - 2020, то получишь "биг бада бум" (С) при попытке считать в строку (с максимальной длиной 255 символов) те же 1010 байт. Буфер надо выделять динамически. Кстати, когда будешь это делать - подумай над тем, что будет, если размер первого файла = 74184 байта, а второго - 222552 байт. Вот когда твоя программа будет отрабатывать и на таких файлах - тогда будем говорить дальше smile.gif Ты сам сказал, что
Цитата
Даны 2 текстовых файла с произвольной информацией внутри
, стало быть, размер файлов может быть тоже произвольным...

TarasBer
> Память - не резиновая, у меня НЕТ свободных 64К, чтобы прочесть в них 800 байт из файла.

64K - для примера. Можно и 4K, или любое удобное число. Поиск числа, на которое делится размер файла, не имеет никакого смысла, кроме как для учебной задачи.

> Потому что МНЕ так хочется. Такой ответ устроит?

Типа как доп.задание? Ну ладно... Главное понимать, что это всего лишь учебное задание, а реального смысла в этом нет.
Krjuger
Цитата
Вот когда твоя программа будет отрабатывать и на таких файлах - тогда будем говорить дальше

А может лучше не надо дальше?)))
Я конешно постараюсь,что что то интузиазм угасает уже)

Цитата
Буфер надо выделять динамически

А тогда по какому принципу записывать в буфер информацию?Например у нас есть.

type
PerconPointer = ^PerconRecord;
PerconRecord = record
temp: string;
Next: PerconPointer
end;


В каждое поле записывать по 255 символов,либо temp будет чаром,но тогда мы недалеко уйдем от считывания по 1 байту.Получается что хоть у нас буфер и будет каким мы заходим,но его заполнение у меня упрется все равно в теже самые 255 символов,более того,если нельзя переписать сразу весь буфер(в данном случае я не знаю можно ли или нет) то наши труды будут весьма сомнительны.В общем то нужен вброс какой то информации,мои знания немного заканчиваются.

P.S.Если вспомнить откуда я брал задачку (методичка для 1 курса) то там решением задачи был бы самый первый код,дальше люди просто не проходили)
TarasBer
Динамический буфер делается не так.
Заводишь тип-указатель на массив максимально возможной длины (65534 байта), выделяешь для него нужное кол-во памяти через GetMem, потом, поработав с ним, освобождаешь через FreeMem
Krjuger
То есть нечто подобное

Buf : array of Char;
FSize : LongWord;
FSize := FileSize(F);
SetLength(Buf, FSize);
BlockRead(F,Pointer(Buf)^, FSize);


ну только собственно в FSize пишеться НОД.
TarasBer
Я думал, у тебя ТурбоПас.
Если у тебя Дельфи, то да, примерно так. Только SetLength(Buf, FSize) - это немного опрометчиво, файлы и на два гига бывают.
IUnknown
Цитата
Заводишь тип-указатель на массив максимально возможной длины (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
Хорошо, пусть будет 65528. Параметры типа ни на что всё равно не влияют в данном случае.
Krjuger
Цитата

думал, у тебя ТурбоПас.
Если у тебя Дельфи, то да, примерно так.

У меня и то и то есть,но как сделать на турбо я вообще не знаю...Хотя сделать надо именно на турбо(
TarasBer
Я же объяснил всё.

type
TBigArr = array [0 .. 65528] of byte;
PBigArr = ^TBigArr;

var
Buf: PBigArr;

...

GetMem(Buf, сколько надо);
...
работаем
...
FreeMem(Buf, сколько было надо, надо освободить ровно столько, сколько и заняли);

Krjuger
Что я делаю не так.

type
TArr= array [0..65528] of byte;
PArr = ^TArr;

function nod(x,y : longint):longint;
begin
if x<>0 then 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);

while not eof(f) and not eof(g) do
begin
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) then
while not eof(g) do
begin
BlockRead(g,b,sizeof(byte));
Blockwrite(f, b,sizeof(byte));
end;
if eof(g) then
while not eof(f) do
begin
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
Цитата
Что я делаю не так.
Хм... Как бы, не надо читать данные туда, где находится сам указатель. Надо читать туда, куда он указывает:

BlockRead(f,b^,ser);
Ты же читал прямо в указатель (и в смежные с ним переменные), разумеется все портил к чертям собачьим, а потом еще и вызывал FreeMem неизвестно какой области (кто знает, что там было в файле, и куда теперь указывают b и p). Еще скажи спасибо, что получаешь "Invalid pointer operation", могло бы по-тихому что-то там освободить, и ты б не узнал, что делаешь что-то не так...

P.S. С записью через BlockWrite - та же петрушка: передавай ей сам буфер, т.е., разыменованный указатель. Да, а кто будет освобождать память после окончательного завершения копирования?
Krjuger
Я пробовал мнооого вариантов в одном из них мой файлик освободился так,что туда 930 мегабайт записалось)))Лан щас дорвусь до компа попробую.

BlockRead(f,b^,ser);


Нечто подолное я видел,но там была связка вида

var
b : ^byte;\\Ну или ^integer, ^real и тд
...........
BlockRead(f,b^,ser);

Krjuger
Так,я совсем запутался.У меня есть b и p ,указатели на массивы байтов,выделить мне память надо для самих массивов так?Если да,то проведя анолонию с предыдущими комметариями я должен вызвать GetMem от разименованного указателя GetMem(b^,ser);
Но сделав это я при компиляции получаю .Poiter variable expected.
IUnknown
Цитата
Если да,то проведя анолонию с предыдущими комметариями я должен вызвать 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 GetMem(var P: Pointer; Size: Word);
procedure FreeMem(var P: Pointer; Size: Word);

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
У меня "семерка" 64 разрядная,так что запускаю я через Dos box, навыков работы с ним у меня мало(практически нет) все что могу это запустить ту программу,что мне нужна.В общем вместо хелпа он мне выдает кучу всяких иероглифоф в которых разобратсья невозможно,понятно,что надо менять кодировку,но где и как, я не знаю.Когда я пытался запускать ЛИСП он вообще отказывался подключать хелп и говорил,что его нету.

В общем исправил,нормально отработало с файлами на 1 КБ и 84 КБ.Но что то мне кажется,что если оба файла будут больше и их кратность будет больше чем 64кб,то тут возникнут проблемы.
Кстати время выполнения уже становится физически ощутимым.(возможно из-за эмулятора).

type
TArr= array [0..65528] of byte;
PArr = ^TArr;

function nod(x,y : longint):longint;
begin
if x<>0 then 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);

while not eof(f) and not eof(g) do
begin
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) then
while not eof(g) do
begin
BlockRead(g,b^,ser);
Blockwrite(f, b^,ser);
end;
if eof(g) then
while not eof(f) do
begin
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.

Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.