Оператор seekp () кажется ненужным, но на самом деле это не так

Следующий код работает с двунаправленными потоками и находит идентификатор записи из файла, а затем заменяет содержимое этой записи из файла. Но перед тем как перезаписать содержимое, он перемещает указатель put в положение указателя get. Через tellp()а также tellg() обнаруживается, что они оба уже были в одном и том же положении перед переключением. А на удаление seekp() строка кода не перезаписывает данные.

Содержание в data.txt:

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 перемещаются вместе?

3

Решение

Вопрос, связанный @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(),

Последний абзац этот ответ дает некоторые аналогичные объяснения.

2

Другие решения

Это потому, что это правило двунаправленных потоков c ++, которое, если кто-то хочет перейти от операции ввода к операции вывода. Тогда нужно использовать seek() функция, чтобы сделать такой сдвиг.

Эта функциональность заимствована из ядра языка c, так как всякий раз, когда кто-то использует двунаправленный поток, программист может работать с двумя разными буферами, в которых один буфер может быть для ввода, а другой для вывода. Теперь синхронизация обоих буферов была бы неэффективным решением. Поскольку большую часть времени программисту может не понадобиться использовать функции ввода и вывода, и программа будет поддерживать оба буфера для программиста без уважительной причины.

В качестве альтернативы этому было реализовано другое решение, позволяющее программисту явно выполнять сброс и другое управление, вызывая seek() функция.

Который означает, что seek() функция, которую мы часто используем, не просто перемещает указатель файла, но также обновляет буферы и поток.

Смотрите также
почему fseek или fflush всегда требуются между чтением и записью в режиме чтения / записи "+" режимы

1

По вопросам рекламы [email protected]