3

如何在 Python 中读取整个文件?我希望我的脚本能够工作,但是它被称为

  • script.py log.txt
  • script.py < log2.txt
  • python script.py < log2.txt
  • python -i script.py logs/yesterday.txt

你明白了。


我试过

import fileinput
from bs4 import BeautifulSoup
f = fileinput.input()
soup = BeautifulSoup(f.read())

但我明白了

Traceback (most recent call last):
  File "visual-studio-extension-load-times.py", line 5, in <module>
    soup = BeautifulSoup(f.read())
AttributeError: FileInput instance has no attribute 'read'
4

6 回答 6

6

不要使用fileinput,而是自己直接打开文件:

import sys
try:
    fileobj = open(sys.argv[1], 'r')
except IndexError:
    fileobj = sys.stdin

with fileobj:
    data = fileobj.read()
于 2013-05-01T15:51:12.630 回答
5
f = open('file.txt', 'r')
data = f.read()
f.close()

此外,要打开从命令行传递的文件,您可以执行以下操作:(此外,这是一种更智能的打开文件的方式,而不是f = open(...)您可以执行的操作with ...

import sys
with open(sys.argv[1], 'r') as f:
    data = f.read()

以更智能的方式打开文件的原因with是因为它会在您离开缩进with块后自动关闭文件。这意味着您不必“担心”文件被打开或被遗忘太久(这可能会导致您的操作系统“打开许多文件句柄”)


然后到sys.argv

sys.argv[1]将是您的 python 文件之后的命令行上的第一个参数。
sys.argv[0]将是您的脚本名称。例如:

python myscript.py heeyooo将会:

  • sys.argv[0] == "myscript.py"
  • sys.argv[1] == "heeyooo":)

然后是在处理文件时你会感兴趣的各种模块。
一方面,os.path这是一个好的开始,因为您很可能希望尽可能多地跨平台,这使您可以选择在 Linux 上转换\/反之亦然。一些好的是:

  • os.path.abspath
  • os.path.is 文件
  • os.path.isdir

你也有os.getcwd()可能是好的:)

于 2013-05-01T15:47:26.517 回答
3

argparse 来救援!:

>>> import sys
>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
...                     default=sys.stdin)
>>> args = parser.parse_args()
>>> file_data = args.infile.read()
于 2013-05-01T16:06:35.817 回答
2
script.py log.txt
script.py < log2.txt

这两个是您脚本的非常不同的调用!首先,shell 将文件名传递log.txt给脚本;其次,shell 将脚本的标准输入连接到文件log2.txt,而脚本实际上从未看到文件名。

可以在同一个脚本处理这两种情况。一种方法是在命令行上没有传递文件时从标准输入中读取。另一种方法是,如果它不是终端,则从标准输入读取,然后读取命令行上列出的文件(如果有)(fileinput如果您有兴趣阅读这些行但不关心它们来自什么文件,我确实喜欢这个)。如果标准输入是终端,您可以使用sys.stdin.isatty()which 返回。True所以是这样的:

import sys, fileinput
if not sys.stdin.isatty():
    for line in sys.stdin:
         process(line)
for line in fileinput.input():
    process(line)

但是,如果您希望将每个文件作为一个整体来处理,就像它出现的那样,那么fileinput就不会这样做。相反,从命令行单独读取每个文件名,读取指示的文件,然后处理它:

import sys
if not sys.stdin.isatty():
    stdin = sys.stdin.read()
    if stdin:
        process(stdin)
for filename in sys.argv[1:]:
    with open(filename) as f:
        process(f.read())

现在关于这些调用:

python script.py < log2.txt
python -i script.py logs/yesterday.txt

就脚本所知,这些与您刚刚script.py直接调用的情况相同,因此您无需专门处理它们。将-i选项输入间接 ( <) 一起使用可能会导致一些意外行为,但我没有尝试过(无论如何也没有任何方法可以解决它)。

于 2013-05-01T16:00:41.483 回答
1

听起来您fileinput一开始并不真正想要,因为您没有尝试连接多个文件,将名称处理-为“将标准输入放在此处”等。

但是,如果您确实想要fileinput,而不是尝试重现其所有行为,只需将其包装起来即可。

您想将所有输入读入一个字符串,但它提供的只是一次为您提供一行或一个文件的函数。所以,你可以做什么?一起加入他们:

soup = BeautifulSoup(''.join(fileinput.input()))

就是这样。

于 2013-05-01T16:46:23.360 回答
0

就这样去了。

import sys
from bs4 import BeautifulSoup
f = open(sys.argv[1] ) if sys.argv[1:] else sys.stdin
soup = BeautifulSoup(f)
于 2013-05-01T16:14:19.100 回答