【问题标题】:File Bytes Array Length Go文件字节数组长度
【发布时间】:2018-10-13 12:31:56
【问题描述】:

我最近开始学习围棋。首先,我决定编写一些代码来打开文件并将其内容输出到终端窗口。到目前为止,我一直在编写这样的代码:

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

data := make([]byte, 100)

count, err := file.Read(data)

从文件中获取最多 100 个字节。有没有办法确定文件的字节数,以便您可以仅使用标准 Go 库设置正确(或更合理)的字节数组长度?

我知道一旦到达数组的末端,您可以使用带有 Append() 之类的切片,但我只是想知道在通过文件元数据实例化数组之前是否可以访问文件大小/长度/任何内容或类似的东西。

【问题讨论】:

  • 请不要这样做。你的问题有答案,但这只是一个糟糕的设计。

标签: arrays go slice


【解决方案1】:

虽然您当然可以在阅读之前获得文件的大小 从中(见另一个答案),这样做通常是徒劳的 出于多种原因:

  • 文件系统本质上是一种活泼的介质:任意数量的进程 可能会同时更新给定文件,甚至删除它。

    在具有 POSIX 语义的文件系统上(大多数商品操作系统 不包括 Windows)是成功打开文件的唯一保证 给你的是可以从中读取数据, 基本上就是这样。 (嗯,读取可能会因为错误而失败 在底层媒体中,但我们不要进一步离题)。

  • 如果你打了相当于fstat(2) 的电话,你会怎么做, 正如建议的那样,它告诉您该文件包含 42 TB 的数据?

    你会尝试分配一个足够大的数组来保存它的内容吗?

    你会实现一些自定义逻辑来分类文件的 大小分成几个范围,并基于此执行自定义处理,例如, 比如说,slurping 长度小于 N 兆字节的文件并读取 更大的文件是零碎的?

  • 如果在获得文件大小后文件变大(被附加到)怎么办?

  • 如果你以后决定更适合 Unix 并让它成为可能怎么办? 从程序的标准输入流中读取数据——比如cat Unix 上的程序(或其type Windows 表亲)可以吗?

    您无法知道有多少数据将通过该流传输; 并且可能它可能是无限长的(考虑用管道 持续运行的系统上某些繁忙日志文件的内容)。

当然,在某些应用程序中,您假设文件的内容不 在你脚下改变;一个例子是像zip 或tar 这样的归档器 与文件一起记录文件的元数据,包括其大小。 (顺便说一下,tar 检测到文件可能在程序发生更改时 正在阅读其内容并在这种情况下警告用户)。

但是我要引导你的是,对于像你这样简单的任务, 以你想出的方式去做没有什么意义。 相反,只需使用一些“合理”大小的缓冲区并网关数据 通过该缓冲区在其源和目标之间。

也就是说,你分配缓冲区,进入一个循环,并在每次迭代 如果您尝试在缓冲区中读取尽可能多的数据,则处理任何内容 Read 函数表明它能够读取,然后处理 文件结束条件或错误(如果已指示)。

为了总结这个小型速成课程,我暗示标准库 已经有io.Copy,在你的 case, 可以这样称呼

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

并将f 的所有内容铲到您的标准输出 程序直到 EOF 或检测到错误。

上次我检查时,这个函数使用了 32 KiB 大小的内部缓冲区, 但你可能总是检查你的 Go 安装的源代码。

【讨论】:

  • 感谢您抽出宝贵的时间来写这篇文章,内容非常丰富。
【解决方案2】:

我假设您需要的是一种方法 get file size in bytes 创建相同大小的切片:

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

(更多信息请参见FileInfo)

然后您可以使用此大小来初始化切片。

data := make([]byte, size)

您也可以考虑使用ioutil.ReadFile 一次通话中的reading the whole file。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    • 2017-01-01
    • 1970-01-01
    相关资源
    最近更新 更多