pwrite () из unistd.h не записывает данные в файл на C ++ - PullRequest
0 голосов
/ 21 апреля 2020

Вот мой фрагмент кода:

void
    DirectIO::writeFileUnix(const std::string &file_path,
                            unsigned long long int index,
                            size_t size,
                            std::string &bytes_data) {
        WRITE_COUNT++;

        const int file_descriptor = open(file_path.c_str(),
                                         O_WRONLY | O_DIRECT | O_SYNC | O_CREAT, S_IRUSR | S_IWUSR);
        if (file_descriptor == -1 || size % SECTOR_SIZE != 0) {
            throw std::exception();
        }

        char *buffer = &bytes_data[0];
        ssize_t number_of_bytes_written = pwrite(file_descriptor, buffer, size, index * size);

        if (number_of_bytes_written == -1 || number_of_bytes_written < size) {
            throw std::exception();
        }

        close(file_descriptor);
    }

Функция выглядит корректно логически. Но number_of_bytes_written всегда равно -1. Файл может быть создан, если не существует. Я не понимаю, почему это не работает.

Обновление 1

Хорошо, значит, у меня проблема. char* buffer ограничен нулевым символом. Следовательно, строка char *buffer = &bytes_data[0]; будет указывать только на небольшую часть строки bytes_data.

Когда я узнал об этом, я обновил эту часть своего кода до

void *buffer = bytes_data.data();
        ssize_t number_of_bytes_written = pwrite(file_descriptor, buffer, size, index * size);

        if (number_of_bytes_written == -1 || number_of_bytes_written < size) {
            throw std::exception();
        }

И data() функция std::string не заботится о нулевых символах в соответствии со своей справочной страницей C ++, а также этой публикацией SO

Но, тем не менее, она не работает .

Если кто-то захочет опробовать код, я публикую здесь свои примерные данные для примерки.

bytes_data - "\000\000\000\000\005\000\000\000\000\000\000\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000....\000" (octal representation as supported by clion)
index = 0
size = 4096 (length of bytes_data)
file_path = "abc.binary"

Обновление 2

Я попытался написать строку, которая не будет иметь нулевой символ, и все же он выдает ошибку. Следовательно, проблема не будет иметь нулевой характер. Это похоже на проблему с выравниванием памяти, так как с выравниванием диска уже позаботились (я могу ошибаться из-за моих ограниченных знаний в C ++).

1 Ответ

1 голос
/ 23 апреля 2020

Как, наконец, уточняется в вопросе, проблема не связана с нулевым символом. Ну, это было в какой-то момент, но измененный код в последнем редактировании убедился, что нулевой символ не вызывает проблем.

С помощью @IanAbbott я обнаружил, что проблема была в (виртуальном) выравнивании памяти. До этого я всегда думал, что для выравнивания требуются только смещения файлов. Но, просмотрев справочную страницу из open(), я обнаружил, что адресное пространство виртуальной памяти также необходимо согласовать с SECTOR_SIZE.

Прочитав еще несколько статей и документов, я обнаружил, что mmap доступно для этой задачи. Адрес, возвращаемый mmap (пространство памяти, сопоставленное с файлом) всегда выравнивается. Поэтому, наконец, я использовал mmap для выполнения задачи, и код выполнялся без ошибок.

...