我正在使用
cat
命令在 Azure Databricks Notebook 中使用 %sh
命令合并多个文件。我的 data_files
文件夹中有大约 1200 个 csv 文件,文件总大小约为 300 GB。当我运行下面的代码时,有时它会合并文件而没有任何错误,但有时会抛出错误 cat: write error: Resource temporarily unavailable
并且创建 output.txt
文件时没有任何数据。
err=$(cat /dbfs/mnt/devl/header_file/*.csv /dbfs/mnt/devl/data_files/*.csv 2>&1 > /dbfs/mnt/devl/output.txt)
RC=$?
if [ $RC -ne 0 ]; then
echo "Error code : $RC"
echo "Error msg : $err"
fi
谁能告诉我错误的根本原因是什么
cat: write error: Resource temporarily unavailable
以及如何解决这个问题?
我无权访问 Azure,但如果我不得不猜测 - 您的问题与目标驱动器的写入速度有关。
解释
写入速度通常比读取速度低几倍,并且如果源文件足够大,应用程序可以读取的数据多于写入的数据,从而填充内核缓冲区。想象一根水管注满一个有小孔的水桶——最终它会被填满。现在,在这种情况下我们有两种不同的行为:
write
调用将等待目标刷新足够的数据,然后恢复写入。write
调用将失败(返回-1
并将errno
设置为EAGAIN
或EWOULDBLOCK
)。这为客户端应用程序提供了很大的灵活性,特别是在多线程用例中 - 但需要显式处理此条件。您正在使用
cat
,它似乎无法处理非阻塞模式 - 并且只会在 EAGAIN
上出错。
解决方法
我在 https://unix.stackexchange.com/questions/613117/cat-resource-temporarily-unavailable:
下的评论中看到了建议的解决方法perl -MFcntl -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) & ~O_NONBLOCK'
或者,您可以寻找一个做得更好的工具 - 或者编写您自己的实用程序。下面是一个小型 Python 脚本的示例,它可以完成您正在寻找的任务。请注意,我只在小文件上测试了它,所以 YMMV。
#!/usr/bin/env python3
import shutil
import os
def concatenate_files(src_filenames: list[str], dst_filename: str) -> None:
with open(dst_filename, 'wb') as outfile:
for infile_name in src_filenames:
with open(infile_name, 'rb') as infile:
shutil.copyfileobj(infile, outfile)
outfile.flush()
os.fsync(outfile.fileno())
if __name__ == "__main__":
# Take command line argument to make it actually useful
input_files = ['file1.dat', 'file2.dat', 'file3.dat']
output_file = 'result.dat'
concatenate_files(input_files, output_file)