написать текстовый файл с одновременным произвольным доступом и добавить - PullRequest
2 голосов
/ 03 марта 2011

Следующий фрагмент кода пытается перезаписать в разных местах в файле, а также добавить в файл. Тем не менее, это не похоже на работу. Я пробовал несколько режимов, и результат либо перезаписывает, либо просто добавляет все в конец файла, но не оба вместе. Возможно ли сделать такую ​​вещь в C ++? Или нам для этого нужно снова и снова открывать файл в разных режимах?

int main() {
  fstream f("a.dat", ios::out | ios::app);
  f.seekp(ios::beg);
  f << "hello world";
  f.seekp(ios::end);
  f << "works";
  return 0;
}

Ответы [ 3 ]

5 голосов
/ 03 марта 2011

Вы хотите вставить данные в файл, который не является концом?В моем опыте нет вставки, по крайней мере, с fstream s.Это очень похоже на запись данных в массив.Просто указатель где-то между началом и концом массива и запись туда не вставляется, а перезаписывается.

Обрабатывайте его так, как если бы вы вставляли данные в середину массива.Вы должны переместить данные вперед, чтобы освободить место для вставки.

Вычислите, сколько места вам понадобится для вставки, и прочитайте все данные после точки вставки в буфер, запишите данные в этот буфер обратно.в файл после того, как вы переместили указатель записи вперед на количество места, которое вам понадобится для вставки.Затем переместите указатель записи обратно туда, куда вы хотели вставить и записать данные, которые вы планируете вставить.

  1. Рассчитать длину данных вставки.
  2. Найти точку вставки.
  3. Чтение остатка файла в буфер.
  4. Поиск в точке вставки.
  5. Запись данных вставки.
  6. Запись из оставшейся части буфера файла.

РЕДАКТИРОВАТЬ: Пример запрашиваемого кода:

#include <fstream>

int main(int argc, char* argv[])
{
    std::fstream FileStream;

    // Initial write.
    FileStream.open("Test.txt", std::ios::out | std::ios::trunc);
    FileStream << "OLDDATAOLDDATA";
    FileStream.close();

    // Prepare data to insert.
    const char InsertionData[] = "newdata";
    const unsigned int InsertionDataLength = strlen(InsertionData);

    // Insertion write.
    FileStream.open("Test.txt", std::ios::in | std::ios::out | std::ios::ate);

    std::ios::pos_type InsertionPosition = 7; // 7 is the start index of the second "OLDDATA".
    FileStream.seekg(0, std::ios::end);
    std::ios::pos_type EndPosition = FileStream.tellg();

    // Read rest of file.
    const unsigned int RestOfFileDataLength = EndPosition - InsertionPosition;
    char* const RestOfFileData = new char[RestOfFileDataLength];
    FileStream.seekg(InsertionPosition);
    FileStream.read(RestOfFileData, RestOfFileDataLength);

    // Rewrite rest of file.
    FileStream.seekp(InsertionPosition);
    FileStream.write(InsertionData, InsertionDataLength);
    FileStream.write(RestOfFileData, RestOfFileDataLength);
    delete[] RestOfFileData;

    FileStream.close();
}

Несколько заметок.Чем раньше в файле, который вы вставляете, тем дороже, потому что вам нужно переместить все после него.Это также означает, что файлы большего размера стоят дороже.Если вы собираетесь сделать несколько вставок, вы можете попытаться отследить каждую вставку и отложить их до тех пор, пока не будет вызвана какая-то команда сброса, после чего требуется только 1 основное чтение / запись остальной части файла, вместо этогоодного для каждого вызова вставки.В идеале, вы должны обернуть это в какую-нибудь собственную упаковку.

4 голосов
/ 03 марта 2011

Если вы укажете ios::app при открытии файла, все записи всегда будут идти в конец файла - в основном, как если бы каждой записи предшествовала f.seekp(ios::end).

Звучит так, как будто вы хотите ios::ate.Он будет искать конец файла сразу после его открытия, но когда / если вы будете искать в другом месте файла и писать, запись будет идти к текущей точке файла вместо конца.

Редактировать 3: Я добавил код для поиска в конце и добавил туда еще:

#include <fstream>
#include <iostream>

int main() { 
    std::fstream f("test.txt", std::ios::in | std::ios::out | std::ios_base::ate);

     f << " added to end.";
     f.seekp(0, std::ios::beg);
     f << "Original";
     f.seekp(0, std::ios::end);
     f << " Final.";

     return 0;
}

Начиная со следующего как содержимое файла "test.txt":

Initial  Value.

После запуска программы файл должен содержать:

Original value. added to end. Final.

Итак, «Добавлено в конец».получает, очевидно, добавляется в конце.Затем мы возвращаемся к началу и перезаписываем «Initial» (плюс один из двух пробелов после него) на «Original».

В качестве отступления, я должен добавить, что, по-видимому, я, по крайней мере, наполовину спал, когдаЯ писал вчера вечером - я полностью упустил тот факт, что вы указали только параметр, когда вызывали seekp. Имея только один параметр, он принимает это как смещение в файл. К сожалению, std::ios::beg, std::ios::cur иstd::ios::end являются простыми целочисленными значениями, поэтому вместо того, чтобы выдавать ошибку типа (как вам бы очень хотелось), она просто брала значение этих перечислений и использовала их как смещения в файле.К счастью, std::ios::beg, по-видимому, имеет значение 0 (по крайней мере, в моей реализации), поэтому оно «сработало», но только случайно. С двумя параметрами (как сейчас имеет приведенный выше код) первый - это смещение, а второй -контрольная точка (начало, текущая позиция или конец), с которой начинается это смещение.

1 голос
/ 03 марта 2011

Что вам нужно знать:

  • Режим добавления пишет в конец файла, независимо от того, какой поиск вы можете делать
  • Даже в других режимах записи, записьв начале файл не добавляется, он перезаписывается.Это не «ошибка» C ++, а файловая система.Это просто способ манипулирования файлами, который будет подходить практически для любой платформы и для каждого языка.
  • Если вы действительно хотите вставить текст в других местах, вам, вероятно, потребуется прочитать файл.в память, манипулируйте ею, затем перезаписывайте файл на диск.Или в некоторых случаях может иметь смысл использовать что-то вроде sed для манипулирования файлом.

Языки, которые предоставляют возможности предварительной подготовки файла из коробки, встречаются редко.Я не знаю ни одного такого, если не считать языки специального назначения, такие как sed, которые не годятся для , но манипуляций с файлами.Могут быть языки, которые делают то, что вы хотите, как вы надеялись, но я не знаю ни одного.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...