ChatGPT解决这个技术问题 Extra ChatGPT

在Ruby中将二进制文件作为字符串读取

我需要一种简单的方法来获取 tar 文件并将其转换为字符串(反之亦然)。有没有办法在 Ruby 中做到这一点?我最好的尝试是这样的:

file = File.open("path-to-file.tar.gz")
contents = ""
file.each {|line|
  contents << line
}

我认为将其转换为字符串就足够了,但是当我尝试像这样将其写回时...

newFile = File.open("test.tar.gz", "w")
newFile.write(contents)

不是同一个文件。执行 ls -l 显示文件大小不同,尽管它们非常接近(打开文件会显示大部分内容完好无损)。我是否犯了一个小错误或完全不同(但可行)的方式来实现这一点?

那是一个压缩的 tar 文件(我希望如此)。没有“线”。请澄清你想要达到的目标。
您是要查看压缩数据还是未压缩内容?
所以压缩数据流中的字符将有大约 256 分之一的机会登陆定义行尾的“\n”,如果它也不期望“\r”也没关系,请参阅下面的答案
此问题应重新命名为“将 binary 文件转换为字符串”,否则 IO.read 将是首选答案。

R
Rory O'Kane

首先,您应该将文件作为二进制文件打开。然后,您可以在一个命令中读取整个文件。

file = File.open("path-to-file.tar.gz", "rb")
contents = file.read

这将使您获得一个字符串中的整个文件。

之后,您可能想要file.close。如果您不这样做,则 file 在被垃圾收集之前不会关闭,因此在它打开时会稍微浪费系统资源。


二进制标志仅在 Windows 上相关,这会使文件描述符保持打开状态。 File.read(...) 更好。
这么多人查找并复制粘贴它作为单行解决方案有什么问题吗(就像stackoverflow上的很多东西一样)?毕竟,它可以工作,而且这些函数的名称只是 ruby 库设计者的任意选择。如果我们有一些带有同义词的语言......它仍然以某种方式确切地知道我们在边缘情况/模棱两可的情况下想要什么。然后我会contents = (contents of file "path to file.txt" as string)
这应该在 begin {..open..} ensure {..close..} end 个块中完成
@ArianFaurtosh 不,这是读取文件的另一种方法——这并不意味着它将被视为可执行文件并运行!对于简单的“读取”方法来说,这将是一个可怕的副作用。
@David 你不能简单地做以下单行吗? contents = File.binread('path-to-file.tar.gz')参见apidockFileIO 的子类。
佚名

如果您需要二进制模式,则需要以艰难的方式进行:

s = File.open(filename, 'rb') { |f| f.read }

如果没有,更短更甜的是:

s = IO.read(filename)

在 ruby 1.9.3+ 中,IO.read 将为您提供一个标有 Encoding.default_external 中编码的字符串。我认为(?)字节将全部与文件中的一样,因此它不完全是“不是二进制安全的”,但是如果您想要的话,您必须用二进制编码对其进行标记。
如果简短和甜蜜是本质,& 符号 proc 技巧给出 s = File.open(filename, 'rb', &:read)
A
Aaron Hinni

为避免文件处于打开状态,最好将块传递给 File.open。这样,文件将在块执行后关闭。

contents = File.open('path-to-file.tar.gz', 'rb') { |f| f.read }

这是一个比 David Nehme 更好的答案,因为文件描述符是有限的系统资源,耗尽它们是一个很容易避免的常见问题。
S
Stu Thompson

一些打开/关闭安全性怎么样。

string = File.open('file.txt', 'rb') { |file| file.read }

为什么不是一个明确的.close?比如在OP file.close 什么时候完成?
File.open() {|文件| block} 在块终止时自动关闭。 ruby-doc.org/core-1.9.3/File.html#method-c-open
这与 2008 年发布的 Aaron Hinni's answer 相同(除了不使用 OP 的文件和变量名)...
P
Purfideas

在 os x 上,这些对我来说是一样的......这可能是 Windows 中额外的“\r”吗?

无论如何,您可能会更好:

contents = File.read("e.tgz")
newFile = File.open("ee.tgz", "w")
newFile.write(contents)

这似乎是最简单的解决方案。
b
bardzo

Ruby 具有二进制读取功能

data = IO.binread(path/filaname)

或者如果低于 Ruby 1.9.2

data = IO.read(path/file)

这是 Ruby 1.9.2+ 的正确答案。
佚名

您可能可以在 Base64 中对 tar 文件进行编码。 Base 64 将为您提供可以存储在纯文本文件中的文件的纯 ASCII 表示。然后,您可以通过将文本解码回来来检索 tar 文件。

你做这样的事情:

require 'base64'

file_contents = Base64.encode64(tar_file_data)

查看 Base64 Rubydocs 以获得更好的想法。


太好了,这看起来也可以!如果由于某种原因读取二进制内容变坏,我将不得不检查它。
D
David Moles

Ruby 1.9+ 有 IO.binread(参见 @bardzo's answer)并且还支持将编码作为选项传递给 IO.read

Ruby 1.9 数据 = File.read(name, {:encoding => 'BINARY'})

Ruby 2+ 数据 = File.read(名称,编码:'BINARY')

(请注意,在这两种情况下,'BINARY' 都是 'ASCII-8BIT'alias。)


J
Joshua Pinter

如果您可以通过 Base64 对 tar 文件进行编码(并将其存储在纯文本文件中),您可以使用

File.open("my_tar.txt").each {|line| puts line}

或者

File.new("name_file.txt", "r").each {|line| puts line}

打印 cmd 中的每一行(文本)。