【问题标题】:numpy.savetxt() stop newline on final linenumpy.savetxt() 在最后一行停止换行
【发布时间】:2015-04-14 02:27:53
【问题描述】:

numpy.savetxt() 似乎总是在文件末尾换行。有没有避免这种行为的好方法?将换行符替换为其他内容没有帮助。

我认为这不是我的代码所特有的,但写作是这样完成的(模型是一个 3D 数组):

np.savetxt(modelFile, model, delimiter=",", fmt='%.3f')

【问题讨论】:

  • 添加了编写代码
  • 可能值得问一下为什么它会有所作为......例如您是否有一些因换行而窒息的关键后处理?
  • 同意@mgilson 关于这一点。但是,使用newline=' ' 选项会让您满意吗?这将删除所有换行符,包括文件末尾的换行符(用空格替换它们)。
  • 如果真的有问题,写完文件后,可以在文件中向后找一个字节(seek(-1, 2)),然后截断...
  • 这是一个有效的问题。我在编写单元测试时遇到了这个问题。由于尾随换行符,savetxt 的输出与预期输出不匹配。

标签: python numpy


【解决方案1】:

我不太确定 为什么 这很重要,或者是否有办法在 numpy 方面阻止它(我在文档中没有看到任何内容......)但你可以可能在写入后在文件中查找然后截断。例如

NEWLINE_SIZE_IN_BYTES = -1  # -2 on Windows?
with open('data.dat', 'w') as fout:
    np.savetxt(fout, model, delimiter=",", fmt='%.3f')
    fout.seek(NEWLINE_SIZE_IN_BYTES, 2)
    fout.truncate()

注意:向后搜索,字节大小必须为负数

【讨论】:

  • 对我不起作用。我得到“UnsupportedOperation:不能做非零末端相对搜索”
【解决方案2】:

解决方案

回答这个问题:有一个很好的方法可以避免这种行为,尽管这取决于你对友善的含义。基本上,您需要做的就是将 numpy.savetxt 函数包装到另一个函数中,或者在任何需要的地方使用此处显示的代码块。

我所做的是将@mgilson's codecode provided 混合在一起,以回答另一个类似问题。简而言之,使用numpy.savetxt 保存文件并删除最后一行的代码将是下一个:

import os

with open('some_array.txt', 'w') as fout:
    NEWLINE_SIZE_IN_BYTES = 1 # 2 on Windows?
    np.savetxt(fout, some_array) # Use np.savetxt.
    fout.seek(0, os.SEEK_END) # Go to the end of the file.
    # Go backwards one byte from the end of the file.
    fout.seek(fout.tell() - NEWLINE_SIZE_IN_BYTES, os.SEEK_SET)
    fout.truncate() # Truncate the file to this point.

os.SEEK_ENDos.SEEK_SET的定义可以在here找到。虽然它们分别只是 2 和 0。

代码背后的逻辑

这里有几点需要注意:

  • 文件以文本模式打开,而不是二进制模式。这很重要,因为如果您不指定编码(我们通常不会像提供给这个问题的两个答案那样),那么在文本模式下从文件中写入和读取取决于平台。例如,换行符在 Windows 或 Linux 中的读取方式不同。来自the documentation

    通常,文件以文本模式打开,这意味着您可以从文件中读取和写入字符串,这些字符串以特定编码进行编码。如果未指定编码,则默认取决于平台(请参阅open())。 (...)

    (...) 在文本模式下,读取时的默认设置是将特定于平台的行尾(Unix 上的\n,Windows 上的\r\n)转换为\n。以文本模式编写时,默认设置是将出现的 \n 转换回特定于平台的行尾。

  • 在下一行代码fout.seek(0, os.SEEK_END) 中,我们将文件的当前位置设置为文件末尾(参见seek() 的参考资料)。这是在 text 模式下从文件末尾开始的唯一合法操作,我将在本文后面引用。

  • 然后,在fout.seek(fout.tell() - NEWLINE_SIZE_IN_BYTES, os.SEEK_SET) 行中,我们只是告诉Python:
    • 将当前位置从当前位置向后设置 1 个字节:fout.tell() - NEWLINE_SIZE_IN_BYTES。其中tell() 仅返回您在reference 中看到的当前位置。
    • 从文件os.SEEK_SET的开头开始。
  • 这样做的原因是,在seek() 方法中,只有tell() 返回的偏移量是合法的,正如seek() 文档中所说:

    如果文件以文本模式打开(没有'b'),只有tell() 返回的偏移量是合法的。使用其他偏移量会导致未定义的行为。

  • 最后,很明显,truncate() 方法只会将文件剪切到当前位置。

二进制模式的另一种方式

我必须声明我现在不太确定在文本模式下这样做是否比在二进制模式下更好虽然其他答案让我这么认为,请参阅其他 question

按照@mgilson's code,我们只需要以二进制模式打开文件。修改后的工作代码为:

NEWLINE_SIZE_IN_BYTES = -1  # -2 on Windows?
with open('data.dat', 'wb') as fout:  # Note 'wb' instead of 'w'
    np.savetxt(fout, model, delimiter=",", fmt='%.3f')
    fout.seek(NEWLINE_SIZE_IN_BYTES, 2)
    fout.truncate()

这两种方式在 Python 版本中都适用于我 > 3.2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 2017-06-30
    相关资源
    最近更新 更多