Следующий код работает с двунаправленными потоками и находит идентификатор записи из файла, а затем заменяет содержимое этой записи из файла. Но перед тем как перезаписать содержимое, он перемещает указатель put в положение указателя get. Через tellp()
а также tellg()
обнаруживается, что они оба уже были в одном и том же положении перед переключением. А на удаление seekp()
строка кода не перезаписывает данные.
123 408-555-0394
124 415-555-3422
263 585-555-3490
100 650-555-3434
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
int inID = 263;
const string& inNewNumber = "777-666-3333";
fstream ioData("data.txt");
// Loop until the end of file
while (ioData.good()) {
int id;
string number;
// Read the next ID.
ioData >> id;
// Check to see if the current record is the one being changed.
if (id == inID) {
cout << "get pointer position " << ioData.tellg() << endl; //Displays 39
cout << "put pointer position " << ioData.tellp() << endl; //Displays 39
ioData.seekp(ioData.tellg()); //Commenting this line stops code from working
ioData << " " << inNewNumber;
break;
}
// Read the current number to advance the stream.
ioData >> number;
}
return 0;
}
Какова необходимость использования seekp()
сместить позицию положенного указателя, если он уже существует, когда указатели get и put перемещаются вместе?
Вопрос, связанный @Revolver_Ocelot в комментариях, дает соответствующую информацию. Самая важная часть состоит в том, что вы должны либо сбрасывать, либо искать между доступом для чтения и записи. Поэтому я изменил ваш код следующим образом:
if (id == inID) {
cout << "get pointer position " << ioData.tellg() << endl; //Displays 39
cout << "put pointer position " << ioData.tellp() << endl; //Displays 39
ioData.flush();
cout << "get pointer position " << ioData.tellg() << endl;
cout << "put pointer position " << ioData.tellp() << endl;
ioData.seekp(ioData.tellg()); //Commenting this line stops code from working
ioData << " " << inNewNumber;
break;
}
Это дает следующий интересный вывод:
получить позицию указателя 39
поставить указатель позиции 39
получить позицию указателя 72
поставить указатель в положение 72
(Calling flush()
на самом деле не решает проблему. Я просто добавил его в ваш код, чтобы показать вам, что он изменяет указатель файла.)
Мое предположение о вашем исходном коде следующее: если вы пишете в свой файл после прочтения, сначала без вызова seekp()
между ними указатель файла изменяется командой write до того, как данные будут фактически записаны в файл. Я предполагаю, что команда записи выполняет некоторую очистку, и это изменяет указатель файла так же, как flush()
Команда, которую я добавил в ваш код.
Когда я запустил код выше на моем ПК, flush()
Команда переместила указатель файла в положение 72. Если мы удалим seekp()
Команда из вашего исходного кода, я думаю, что команда записи также переместит указатель файла в позицию 72 (или, возможно, другую недопустимую позицию) перед фактической записью в файл. В этом случае запись не удалась, потому что позиция 72 находится за концом файла.
Как следствие, ioData.seekp(ioData.tellg());
необходим для того, чтобы указатель файла был установлен на правильную позицию файла, потому что он может меняться при переключении между чтением и записью в файл без вызова seekp()
,
Последний абзац этот ответ дает некоторые аналогичные объяснения.
Это потому, что это правило двунаправленных потоков c ++, которое, если кто-то хочет перейти от операции ввода к операции вывода. Тогда нужно использовать seek()
функция, чтобы сделать такой сдвиг.
Эта функциональность заимствована из ядра языка c, так как всякий раз, когда кто-то использует двунаправленный поток, программист может работать с двумя разными буферами, в которых один буфер может быть для ввода, а другой для вывода. Теперь синхронизация обоих буферов была бы неэффективным решением. Поскольку большую часть времени программисту может не понадобиться использовать функции ввода и вывода, и программа будет поддерживать оба буфера для программиста без уважительной причины.
В качестве альтернативы этому было реализовано другое решение, позволяющее программисту явно выполнять сброс и другое управление, вызывая seek()
функция.
Который означает, что seek()
функция, которую мы часто используем, не просто перемещает указатель файла, но также обновляет буферы и поток.
Смотрите также
почему fseek или fflush всегда требуются между чтением и записью в режиме чтения / записи "+" режимы