Файл Байт Длина массива Go - PullRequest
0 голосов
/ 03 мая 2018

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

file, err := os.Open("./blah.txt")

data := make([]byte, 100)

count, err := file.Read(data)

Для получения до 100 байтов из файла. Есть ли способ определить количество байтов в файле, чтобы вы могли установить правильную (или более разумную) длину байтового массива, просто используя стандартную библиотеку Go?

Я понимаю, что вы могли бы использовать фрагмент с чем-то вроде Append(), как только были достигнуты конечные значения массива, но я просто подумал, можно ли получить доступ к размеру / длине файла / какому-либо другому объекту до создания экземпляра массива с помощью метаданных файла или нечто подобное.

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

Хотя вы, конечно, можете получить размер файла до чтения Исходя из этого (см. другой ответ), делать это обычно бесполезно по ряду причин:

  • Файловая система - это по своей природе колоритный носитель: любое количество процессов может обновить данный файл одновременно и даже удалить его.

    В файловой системе с семантикой POSIX (большинство обычных ОС кроме Windows) единственная гарантия успешного открытия файла дает вам то, что можно читать данные из него, и это в основном все. (Ну, чтение может произойти сбой из-за ошибки в основной информации, но давайте не будем отступать дальше).

  • Что бы вы сделали, если бы вы сделали эквивалент вызова fstat(2), как предложено, и он сказал вам, что файл содержит 42 терабайта данных?

    Вы бы попытались выделить достаточно большой массив для хранения его содержимого?

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

  • Что, если файл увеличился (был добавлен) после того, как вы получили его размер?

  • Что если позже вы решите быть более подготовленными к Unix и сделаете это возможным читать данные из стандартного потока ввода вашей программы - например, cat программа на Unix (или ее type Windows двоюродный брат) делает?

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

Конечно, в некоторых приложениях вы предполагаете, содержимое файлов не переодеться под ногами; Одним из примеров являются архиваторы, такие как zip или tar, которые запишите метаданные файла, включая его размер, вместе с файлом. (Кстати, tar обнаруживает, что файл мог измениться, пока программа читал его содержимое и предупреждает пользователя в этом случае).

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

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

Чтобы округлить этот небольшой ускоренный курс, я бы намекнул, что стандартная библиотека уже имеет io.Copy, который в вашем случай, может быть назван как

_, err := io.Copy(os.Stdout, f)

и переложит все содержимое f на стандартный вывод вашего запрограммируйте до EOF или до обнаружения ошибки.

В прошлый раз, когда я проверял, эта функция использовала внутренний буфер размером 32 КиБ, но вы всегда можете проверить исходный код вашей установки Go.

0 голосов
/ 03 мая 2018

Я предполагаю, что вам нужен способ получить размер файла в байтах , чтобы создать срез того же размера:

f, err := f.Stat()
// handle error 
// ...
size := f.Size()

(подробнее см. FileInfo )

Затем вы можете использовать этот размер для инициализации среза.

data := make([]byte, size)

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

...