解决方案
回答这个问题:有一个很好的方法可以避免这种行为,尽管这取决于你对友善的含义。基本上,您需要做的就是将 numpy.savetxt 函数包装到另一个函数中,或者在任何需要的地方使用此处显示的代码块。
我所做的是将@mgilson's code 与code 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_END和os.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。