如何逐字阅读文件

时间:2014-10-16 04:16:11

标签: python python-2.7

我有一个PPM文件,我需要对其进行某些操作。该文件的结构如下例所示。第一行,'P3'只是说它是什么样的文件。在第二行中,它给出了图像的像素尺寸,因此在这种情况下,它告诉我们图像是480x640。在第三行中,它声明了任何颜色可以采用的最大值。之后会有代码行。每三个整数组给出一个像素的rbg值。所以在这个例子中,第一个像素的rgb值为49,49,49。第二个像素的rgb值为48,48,48,依此类推。

P3
480 640
255
49   49   49   48   48   48   47   47   47   46   46   46   45   45   45   42   42   42   38   38   
38   35   35   35   23   23   23   8   8   8   7   7   7   17   17   17   21   21   21   29   29   
29   41   41   41   47   47   47   49   49   49   42   42   42   33   33   33   24   24   24   18   18   
...

现在您可能已经注意到,此特定图片应为640像素宽,这意味着640 * 3整数将提供第一行像素。但是这里第一行非常非常远,包含640 * 3个整数。所以这个文件中的换行没有意义,因此我的问题。

读取Python文件的主要方法是逐行。但我需要将这些整数收集到640 * 3的组中并将其视为一条线。怎么会这样做?我知道我可以逐行读取文件并将每一行附加到某个列表,但是那个列表会很大,我认为这样做会给设备的内存带来不可接受的负担。但除此之外,我没有想法。帮助将不胜感激。

5 个答案:

答案 0 :(得分:3)

从文件中一次读取三个以空格分隔的单词:

with open(filename, 'rb') as file:
    kind, dimensions, max_color = map(next, [file]*3) # read 3 lines
    rgbs = zip(*[(int(word) for line in file for word in line.split())] * 3)

Output

[(49, 49, 49),
 (48, 48, 48),
 (47, 47, 47),
 (46, 46, 46),
 (45, 45, 45),
 (42, 42, 42),
 ...

请参阅What is the most “pythonic” way to iterate over a list in chunks?

为避免一次创建列表,您可以使用允许一次读取一个rgb值的itertools.izip()

答案 1 :(得分:2)

可能不是最'pythonic'的方式,但......

遍历包含整数的行。

保留四个计数 - 计数3 - color_code_count,计数1920 - numbers_processed,count - col(0-639),另一个 - 行(0-479)。

对于您遇到的每个整数,将其添加到list [color_code_count]索引的临时列表中。增加color_code_count,col和numbers_processed。

一旦color_code_count为3,你就可以获取你的临时列表并创建一个元组3或三元组(不确定该术语是什么,但第一个像素的结构看起来像(49,49,49)),并将其添加到640列和480行的列表 - 将您的(49,49,49)插入像素[col] [row]。

增量col。 重置color_code_count。
'numbers_processed'将继续增加,直到你到达1920.

一旦你达到1920,你已经到了第一行的末尾 将numbers_processed和col重置为零,将行递增1.

此时,你应该在第0行中有640个tuple3或三元组,从(49,49,49),(48,48,48),(47,47,47)等开始。等等。现在开始在第1行第0列插入像素值。

像我说的那样,可能不是最“py”的方式。使用join和map可能有更好的方法来实现这一点,但我认为这可能有用吗?这个“解决方案”,如果你想要它,它不应该关心任何一行上的整数,因为你在开始一个新行之前要计算你希望运行的数量(1920)。

答案 2 :(得分:0)

遍历每个单词的一种可能方法是遍历每一行,然后.split遍历每个单词。

the_file = open("file.txt",r)

for line in the_file:
    for word in line.split():
        #-----Your Code-----     

从那里你可以用你的"单词做任何你想做的事。"您可以添加if-statements来检查每行中是否有数字:(虽然不是非常pythonic)

for line in the_file:
    if "1" not in line or "2" not in line ...:
        for word in line.split():
            #-----Your Code-----

或者你可以测试每行中是否有任何东西:(更多pythonic)

for line in the_file:
    for word in line.split():
        if len(word) != 0 or word != "\n":
            #-----Your Code-----    

我建议你添加新的"线"到新文件。

答案 3 :(得分:0)

我是C程序员。对不起,如果此代码看起来像C Style

f = open("pixel.ppm", "r")
type = f.readline()
height, width = f.readline().split()
height, width = int(height), int(width)
max_color = int(f.readline());
colors = []
count = 0
col_count = 0
line = []
while(col_count < height):
    count = 0
    i = 0
    row =[]
    while(count < width * 3):
        temp = f.readline().strip()
        if(temp == ""):
            col_count = height
            break
        temp = temp.split()
        line.extend(temp)
        i = 0
        while(i + 2 < len(line)):
            row.append({'r':int(line[i]),'g':int(line[i+1]),'b':int(line[i+2])})
            i = i+3
            count = count +3
            if(count >= width *3):
                break
        if(i < len(line)):
            line = line[i:len(line)]
        else:
            line = []
    col_count += 1
    colors.append(row)
for row in colors:
    for rgb in row:
        print(rgb)
    print("\n")

您可以根据需要进行调整。我在这个文件上测试了它:

P4
3 4
256
4 5 6 4 7 3
2 7 9 4
2 4
6 8 0 
3 4 5 6 7 8 9 0 
2 3 5 6 7 9 2 
2 4 5 7 2 
2

答案 4 :(得分:0)

这似乎可以解决问题:

from re import findall

def _split_list(lst, i):
    return lst[:i], lst[i:]

def iter_ppm_rows(path):
    with open(path) as f:
        ftype = f.readline().strip()
        h, w = (int(s) for s in f.readline().split(' '))
        maxcolor = int(f.readline())

        rlen = w * 3
        row = []
        next_row = []

        for line in f:
            line_ints = [int(i) for i in findall('\d+\s+', line)]

            if not row:
                row, next_row = _split_list(line_ints, rlen)
            else:
                rest_of_row, next_row = _split_list(line_ints, rlen - len(row))
                row += rest_of_row

            if len(row) == rlen:
                yield row
                row = next_row
                next_row = []

它不是很漂亮,但它允许在文件中的数字之间改变空格,以及不同的行长度。

我在一个看起来如下的文件上测试了它:

P3
120 160
255
0   1   2   3   4   5   6   7   
8   9   10   11   12   13   
14   15   16   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32   33   34   
[...]
9993   9994   9995   9996   9997   9998   9999   

该文件使用随机行长度,但按顺序打印数字,因此很容易判断行开始和停止的值。请注意,其尺寸与问题的示例文件中的尺寸不同。

使用以下测试代码......

for row in iter_ppm_rows('mock_ppm.txt'): 
    print(len(row), row[0], row[-1])

...结果如下,似乎没有跳过任何数据并返回正确大小的行。

480 0 479
480 480 959
480 960 1439
480 1440 1919
480 1920 2399
480 2400 2879
480 2880 3359
480 3360 3839
480 3840 4319
480 4320 4799
480 4800 5279
480 5280 5759
480 5760 6239
480 6240 6719
480 6720 7199
480 7200 7679
480 7680 8159
480 8160 8639
480 8640 9119
480 9120 9599

可以看出,文件末尾的不能代表完整行的跟踪数据没有产生,这是预期的,但您可能想以某种方式解释它。