如何以相反的顺序读取文件?


128

如何使用python以相反的顺序读取文件?我想从最后一行读取文件。


7
您是说“按相反顺序阅读”还是“按相反顺序处理行”?有区别。对于第一个文件,可能该文件可能无法一次全部放入内存,因此您想以相反的顺序处理行,但是无法读取整个文件并将其反转。对于第二个,您可能只是读入了整个文件,并在处理它们之前反转了行列表。那是什么呢?
Lasse V. Karlsen


1
我建议这样做-不会出现内存问题,而且速度很快:stackoverflow.com/a/260433/1212562
Brian B

Answers:


73
for line in reversed(open("filename").readlines()):
    print line.rstrip()

在Python 3中:

for line in reversed(list(open("filename"))):
    print(line.rstrip())

192
las,如果您无法在内存中容纳整个文件,则此方法将无效。
vy32 2010年

3
另外,虽然发布的代码确实回答了问题,但我们应谨慎关闭打开的文件。该with声明通常非常轻松。
威廉

1
@MichaelDavidWatson:并非不先将原始迭代器读入内存,然后在第一个迭代器上反向显示一个新的迭代器。
马特·乔纳

3
@MichaelDavidWatson:您可以反向读取文件而无需将其读取到内存中,但这是不平凡的,并且需要大量的缓冲区恶作剧,以避免大量的系统调用浪费。它的性能也会很差(如果文件超出了可用内存,则比将整个内存读入内存要好)。
马特·乔纳

1
@William对不起,如何遍历文件然后清理关闭文件时使用“ with open”的上述解决方案?
BringBackCommodore17年

146

作为生成器编写的正确,有效的答案。

import os

def reverse_readline(filename, buf_size=8192):
    """A generator that returns the lines of a file in reverse order"""
    with open(filename) as fh:
        segment = None
        offset = 0
        fh.seek(0, os.SEEK_END)
        file_size = remaining_size = fh.tell()
        while remaining_size > 0:
            offset = min(file_size, offset + buf_size)
            fh.seek(file_size - offset)
            buffer = fh.read(min(remaining_size, buf_size))
            remaining_size -= buf_size
            lines = buffer.split('\n')
            # The first line of the buffer is probably not a complete line so
            # we'll save it and append it to the last line of the next buffer
            # we read
            if segment is not None:
                # If the previous chunk starts right from the beginning of line
                # do not concat the segment to the last line of new chunk.
                # Instead, yield the segment first 
                if buffer[-1] != '\n':
                    lines[-1] += segment
                else:
                    yield segment
            segment = lines[0]
            for index in range(len(lines) - 1, 0, -1):
                if lines[index]:
                    yield lines[index]
        # Don't yield None if the file was empty
        if segment is not None:
            yield segment

4
这对于python> = 3.2中的文本文件将不起作用,因为出于某种原因,不再支持相对于文件末尾的查找。可以通过保存的返回文件的大小是固定的fh.seek(0, os.SEEK_END),并改变fh.seek(-offset, os.SEEK_END)fh.seek(file_size - offset)
levesque 2015年

9
完成编辑后,这在python 3.5中可以完美工作。最佳答案的问题。
notbad.jpeg,2016年

3
在python 2中恢复此更改,其中fh.seek()返回None
marengaz

1
请注意,这对于文本文件可能无法正常工作。以相反的顺序正确获取块仅适用于二进制文件。的问题是,用于与多字节编码(例如文本文件utf8),seek()以及read()指的是不同的尺寸。这也可能是为什么不支持seek()相对于first的非零参数的原因os.SEEK_END
norok2

3
简单:'aöaö'.encode()b'a\xc3\xb6a\xc3\xb6'。如果将其保存到磁盘上,然后以文本模式读取,seek(2)则将其移动两个字节,这seek(2); read(1)将导致错误UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb6 in position 0: invalid start byte,但是,如果这样做seek(0); read(2); read(1),则会得到'a'您所期望的,即:seek()从不编码-aware,read()即您是否以文本模式打开文件。现在,如果具有'aöaö' * 1000000,则您的块将无法正确对齐。
norok2 '18

23

这样的事情怎么样:

import os


def readlines_reverse(filename):
    with open(filename) as qfile:
        qfile.seek(0, os.SEEK_END)
        position = qfile.tell()
        line = ''
        while position >= 0:
            qfile.seek(position)
            next_char = qfile.read(1)
            if next_char == "\n":
                yield line[::-1]
                line = ''
            else:
                line += next_char
            position -= 1
        yield line[::-1]


if __name__ == '__main__':
    for qline in readlines_reverse(raw_input()):
        print qline

由于文件是按相反的顺序逐个字符读取的,因此即使在非常大的文件中也可以使用,只要将单独的行放入内存中即可。


20

您也可以使用python模块 file_read_backwards

通过pip install file_read_backwards(v1.2.1)安装后,您可以通过以下方式以内存高效的方式向后(逐行)读取整个文件:

#!/usr/bin/env python2.7

from file_read_backwards import FileReadBackwards

with FileReadBackwards("/path/to/file", encoding="utf-8") as frb:
    for l in frb:
         print l

它支持“ utf-8”,“ latin-1”和“ ascii”编码。

也支持python3。可以在http://file-read-backwards.readthedocs.io/en/latest/readme.html上找到更多文档。


感谢您的解决方案。我喜欢(也赞成)@srohde的上述解决方案,因为它可以帮助我理解它的完成方式,但是作为开发人员,我更愿意在可能的情况下使用现有的模块,因此,我很高兴知道这一点。
joanis

1
这适用于像UTF-8这样的多字节编码。查找/读取解决方案没有:seek()以字节为单位,read()以字符为单位。
Jeremitu

9
for line in reversed(open("file").readlines()):
    print line.rstrip()

如果您使用的是Linux,则可以使用taccommand。

$ tac file

您可以在ActiveState的此处此处找到2个食谱


1
我想知道reversed()是否在迭代之前消耗了整个序列。医生说__reversed__()需要一个方法,但是python2.5不会抱怨没有它的自定义类。
muhuk 2010年

@muhuk,它可能必须以某种方式缓存它,我怀疑它会以相反的顺序生成一个新列表,然后向该列表返回一个迭代器
Matt Joiner 2010年

1
@马特:太荒谬了。它只是从后面到前面-len(L)-1是后面,0是前面。您可以想象其余的。
Devin Jeanpierre

@muhuk:序列没有被有意义地消耗(您可以遍历整个序列,但这并不重要)。一个__reversed__方法也没有必要,有没有用是这样的事情。如果提供一个对象__len____getitem__它将正常工作(减去一些例外情况,例如dict)。
Devin Jeanpierre

@Devin Jeanpierre:只有readlines方法()返回一个对象,它提供__reversed__
马特·乔纳

8
import re

def filerev(somefile, buffer=0x20000):
  somefile.seek(0, os.SEEK_END)
  size = somefile.tell()
  lines = ['']
  rem = size % buffer
  pos = max(0, (size // buffer - 1) * buffer)
  while pos >= 0:
    somefile.seek(pos, os.SEEK_SET)
    data = somefile.read(rem + buffer) + lines[0]
    rem = 0
    lines = re.findall('[^\n]*\n?', data)
    ix = len(lines) - 2
    while ix > 0:
      yield lines[ix]
      ix -= 1
    pos -= buffer
  else:
    yield lines[0]

with open(sys.argv[1], 'r') as f:
  for line in filerev(f):
    sys.stdout.write(line)

对于大于缓冲区的文件,这似乎产生了错误的输出。据我了解,它无法正确处理跨越读取的缓冲区大小的块的行。我发布了另一个类似的答案(针对另一个类似的问题)。
大流士培根

@Darius:啊,是的,我似乎错过了一点。现在应该修复。
伊格纳西奥·巴斯克斯

看起来不错。我仍然希望使用自己的代码,因为这会使O(N ^ 2)在只占一行的大文件上工作。(在我测试过的另一个问题的类似答案中,此类文件导致了真正的严重减速。)
Darius Bacon

3
好了,这个问题没有提到性能,所以我不能挑剔是正则表达式的性能灾难:P
Matt Joiner 2010年

如果性能确实可以寻求让我们说出最后一行并仅阅读该文章,则更多的解释将有助于提高性能。
user1767754

7

接受的答案不适用于文件大而内存不足的情况(这种情况很少见)。

正如其他人所指出的那样,@ srohde的答案看起来不错,但存在下一个问题:

  • 当我们可以传递文件对象并将其留给用户来决定应以哪种编码方式读取文件时,打开文件看起来是多余的,
  • 即使我们重构为接受文件对象,它也不适用于所有编码:我们可以选择具有utf-8编码和非ascii内容的文件,例如

    й

    通过buf_size等于1并将具有

    UnicodeDecodeError: 'utf8' codec can't decode byte 0xb9 in position 0: invalid start byte

    当然文字可能更大,但 buf_size可能会被拾取,从而导致上述混淆错误,

  • 我们无法指定自定义行分隔符,
  • 我们不能选择保留行分隔符。

因此,考虑到所有这些问题,我编写了单独的函数:

  • 一种适用于字节流的
  • 第二个用于文本流,并将其基础字节流委托给第一个,并解码结果行。

首先,让我们定义下一个实用程序函数:

ceil_division用于天花板分隔(与标准//地板分隔相反,更多信息可以在此线程中找到)

def ceil_division(left_number, right_number):
    """
    Divides given numbers with ceiling.
    """
    return -(-left_number // right_number)

split 通过从右端给定的分隔符分割字符串并保持其能力:

def split(string, separator, keep_separator):
    """
    Splits given string by given separator.
    """
    parts = string.split(separator)
    if keep_separator:
        *parts, last_part = parts
        parts = [part + separator for part in parts]
        if last_part:
            return parts + [last_part]
    return parts

read_batch_from_end 从二进制流的右端读取批处理

def read_batch_from_end(byte_stream, size, end_position):
    """
    Reads batch from the end of given byte stream.
    """
    if end_position > size:
        offset = end_position - size
    else:
        offset = 0
        size = end_position
    byte_stream.seek(offset)
    return byte_stream.read(size)

之后,我们可以定义函数以相反的顺序读取字节流,例如

import functools
import itertools
import os
from operator import methodcaller, sub


def reverse_binary_stream(byte_stream, batch_size=None,
                          lines_separator=None,
                          keep_lines_separator=True):
    if lines_separator is None:
        lines_separator = (b'\r', b'\n', b'\r\n')
        lines_splitter = methodcaller(str.splitlines.__name__,
                                      keep_lines_separator)
    else:
        lines_splitter = functools.partial(split,
                                           separator=lines_separator,
                                           keep_separator=keep_lines_separator)
    stream_size = byte_stream.seek(0, os.SEEK_END)
    if batch_size is None:
        batch_size = stream_size or 1
    batches_count = ceil_division(stream_size, batch_size)
    remaining_bytes_indicator = itertools.islice(
            itertools.accumulate(itertools.chain([stream_size],
                                                 itertools.repeat(batch_size)),
                                 sub),
            batches_count)
    try:
        remaining_bytes_count = next(remaining_bytes_indicator)
    except StopIteration:
        return

    def read_batch(position):
        result = read_batch_from_end(byte_stream,
                                     size=batch_size,
                                     end_position=position)
        while result.startswith(lines_separator):
            try:
                position = next(remaining_bytes_indicator)
            except StopIteration:
                break
            result = (read_batch_from_end(byte_stream,
                                          size=batch_size,
                                          end_position=position)
                      + result)
        return result

    batch = read_batch(remaining_bytes_count)
    segment, *lines = lines_splitter(batch)
    yield from reverse(lines)
    for remaining_bytes_count in remaining_bytes_indicator:
        batch = read_batch(remaining_bytes_count)
        lines = lines_splitter(batch)
        if batch.endswith(lines_separator):
            yield segment
        else:
            lines[-1] += segment
        segment, *lines = lines
        yield from reverse(lines)
    yield segment

最后,可以将文本文件反转功能定义如下:

import codecs


def reverse_file(file, batch_size=None, 
                 lines_separator=None,
                 keep_lines_separator=True):
    encoding = file.encoding
    if lines_separator is not None:
        lines_separator = lines_separator.encode(encoding)
    yield from map(functools.partial(codecs.decode,
                                     encoding=encoding),
                   reverse_binary_stream(
                           file.buffer,
                           batch_size=batch_size,
                           lines_separator=lines_separator,
                           keep_lines_separator=keep_lines_separator))

测验

准备工作

我已经使用fsutilcommand生成了4个文件:

  1. 没有内容的empty.txt,大小为0MB
  2. tiny.txt,大小为1MB
  3. small.txt,大小为10MB
  4. large.txt,大小为50MB

我也重构了@srohde解决方案以使用文件对象而不是文件路径。

测试脚本

from timeit import Timer

repeats_count = 7
number = 1
create_setup = ('from collections import deque\n'
                'from __main__ import reverse_file, reverse_readline\n'
                'file = open("{}")').format
srohde_solution = ('with file:\n'
                   '    deque(reverse_readline(file,\n'
                   '                           buf_size=8192),'
                   '          maxlen=0)')
azat_ibrakov_solution = ('with file:\n'
                         '    deque(reverse_file(file,\n'
                         '                       lines_separator="\\n",\n'
                         '                       keep_lines_separator=False,\n'
                         '                       batch_size=8192), maxlen=0)')
print('reversing empty file by "srohde"',
      min(Timer(srohde_solution,
                create_setup('empty.txt')).repeat(repeats_count, number)))
print('reversing empty file by "Azat Ibrakov"',
      min(Timer(azat_ibrakov_solution,
                create_setup('empty.txt')).repeat(repeats_count, number)))
print('reversing tiny file (1MB) by "srohde"',
      min(Timer(srohde_solution,
                create_setup('tiny.txt')).repeat(repeats_count, number)))
print('reversing tiny file (1MB) by "Azat Ibrakov"',
      min(Timer(azat_ibrakov_solution,
                create_setup('tiny.txt')).repeat(repeats_count, number)))
print('reversing small file (10MB) by "srohde"',
      min(Timer(srohde_solution,
                create_setup('small.txt')).repeat(repeats_count, number)))
print('reversing small file (10MB) by "Azat Ibrakov"',
      min(Timer(azat_ibrakov_solution,
                create_setup('small.txt')).repeat(repeats_count, number)))
print('reversing large file (50MB) by "srohde"',
      min(Timer(srohde_solution,
                create_setup('large.txt')).repeat(repeats_count, number)))
print('reversing large file (50MB) by "Azat Ibrakov"',
      min(Timer(azat_ibrakov_solution,
                create_setup('large.txt')).repeat(repeats_count, number)))

注意:我已经使用了collections.deque类来耗尽生成器。

产出

对于Windows 10上的PyPy 3.5:

reversing empty file by "srohde" 8.31e-05
reversing empty file by "Azat Ibrakov" 0.00016090000000000028
reversing tiny file (1MB) by "srohde" 0.160081
reversing tiny file (1MB) by "Azat Ibrakov" 0.09594989999999998
reversing small file (10MB) by "srohde" 8.8891863
reversing small file (10MB) by "Azat Ibrakov" 5.323388100000001
reversing large file (50MB) by "srohde" 186.5338368
reversing large file (50MB) by "Azat Ibrakov" 99.07450229999998

对于Windows 10上的CPython 3.5:

reversing empty file by "srohde" 3.600000000000001e-05
reversing empty file by "Azat Ibrakov" 4.519999999999958e-05
reversing tiny file (1MB) by "srohde" 0.01965560000000001
reversing tiny file (1MB) by "Azat Ibrakov" 0.019207699999999994
reversing small file (10MB) by "srohde" 3.1341862999999996
reversing small file (10MB) by "Azat Ibrakov" 3.0872588000000007
reversing large file (50MB) by "srohde" 82.01206720000002
reversing large file (50MB) by "Azat Ibrakov" 82.16775059999998

因此,我们可以看到它的性能像原始解决方案一样,但它更具通用性,并且没有上面列出的缺点。


广告

我已经将此添加到具有许多经过良好测试的功能/迭代实用程序0.3.0lz软件包版本(需要Python 3.5 +)中。

可以像

 import io
 from lz.iterating import reverse
 ...
 with open('path/to/file') as file:
     for line in reverse(file, batch_size=io.DEFAULT_BUFFER_SIZE):
         print(line)

它支持所有标准编码(可能utf-7是因为我很难定义一种策略来生成可编码的字符串)。


2

在这里,您可以找到我的实现,可以通过更改“ buffer”变量来限制ram的使用,这是一个程序在开始时打印空行的错误。

如果没有新行超过缓冲区字节,内存使用也会增加,“ leak”变量将一直增加,直到看到新行(“ \ n”)为止。

这也适用于大于我的总内存的16 GB文件。

import os,sys
buffer = 1024*1024 # 1MB
f = open(sys.argv[1])
f.seek(0, os.SEEK_END)
filesize = f.tell()

division, remainder = divmod(filesize, buffer)
line_leak=''

for chunk_counter in range(1,division + 2):
    if division - chunk_counter < 0:
        f.seek(0, os.SEEK_SET)
        chunk = f.read(remainder)
    elif division - chunk_counter >= 0:
        f.seek(-(buffer*chunk_counter), os.SEEK_END)
        chunk = f.read(buffer)

    chunk_lines_reversed = list(reversed(chunk.split('\n')))
    if line_leak: # add line_leak from previous chunk to beginning
        chunk_lines_reversed[0] += line_leak

    # after reversed, save the leakedline for next chunk iteration
    line_leak = chunk_lines_reversed.pop()

    if chunk_lines_reversed:
        print "\n".join(chunk_lines_reversed)
    # print the last leaked line
    if division - chunk_counter < 0:
        print line_leak

2

感谢您的回答@srohde。它使用“ is”运算符检查换行符时有一个小错误,并且我无法对信誉为1的答案进行评论。我也想管理外部文件的打开,因为这使我可以将杂物嵌入luigi任务。

我需要更改的形式如下:

with open(filename) as fp:
    for line in fp:
        #print line,  # contains new line
        print '>{}<'.format(line)

我想更改为:

with open(filename) as fp:
    for line in reversed_fp_iter(fp, 4):
        #print line,  # contains new line
        print '>{}<'.format(line)

这是修改后的答案,需要文件句柄并保留换行符:

def reversed_fp_iter(fp, buf_size=8192):
    """a generator that returns the lines of a file in reverse order
    ref: https://stackoverflow.com/a/23646049/8776239
    """
    segment = None  # holds possible incomplete segment at the beginning of the buffer
    offset = 0
    fp.seek(0, os.SEEK_END)
    file_size = remaining_size = fp.tell()
    while remaining_size > 0:
        offset = min(file_size, offset + buf_size)
        fp.seek(file_size - offset)
        buffer = fp.read(min(remaining_size, buf_size))
        remaining_size -= buf_size
        lines = buffer.splitlines(True)
        # the first line of the buffer is probably not a complete line so
        # we'll save it and append it to the last line of the next buffer
        # we read
        if segment is not None:
            # if the previous chunk starts right from the beginning of line
            # do not concat the segment to the last line of new chunk
            # instead, yield the segment first
            if buffer[-1] == '\n':
                #print 'buffer ends with newline'
                yield segment
            else:
                lines[-1] += segment
                #print 'enlarged last line to >{}<, len {}'.format(lines[-1], len(lines))
        segment = lines[0]
        for index in range(len(lines) - 1, 0, -1):
            if len(lines[index]):
                yield lines[index]
    # Don't yield None if the file was empty
    if segment is not None:
        yield segment

1

一个简单的函数来创建另一个反转的文件(仅适用于Linux):

import os
def tac(file1, file2):
     print(os.system('tac %s > %s' % (file1,file2)))

如何使用

tac('ordered.csv', 'reversed.csv')
f = open('reversed.csv')

我认为目标是如何在Python中做到这一点。另外,尽管这是一个出色的解决方案,但它仅适用于* Nix系统。从本质上讲,它只是使用Python作为运行Shell实用程序的提示。
Alexander Huszagh '16

1
该代码具有当前编写的主要安全错误。如果您尝试撤消使用创建的文件怎么办mv mycontent.txt $'hello $(rm -rf $HOME) world.txt'使用或类似地使用不受信任用户指定的输出文件名的文件,该怎么办?如果要安全地处理任意文件名,则要格外小心。subprocess.Popen(['tac', file1], stdout=open(file2, 'w'))例如,将是安全的。
查尔斯·达菲

现有代码也无法正确处理带有空格,通配符&c的文件。
查尔斯·达菲


1

使用open(“ filename”)as f:

    print(f.read()[::-1])

这会读取整个文件吗?大文件安全吗?这似乎是一种非常简单且现实的方法,但是不确定上述问题。.我想以这种方式搜索文件(使用re)
。–

@ ikwyl6这应该等效于list(reversed(f.read()))
AMC


0

with处理文件时请务必使用,因为它可以为您处理所有事情:

with open('filename', 'r') as f:
    for line in reversed(f.readlines()):
        print line

或在Python 3中:

with open('filename', 'r') as f:
    for line in reversed(list(f.readlines())):
        print(line)

0

您需要首先以读取格式打开文件,将其保存到变量,然后以写入格式打开第二个文件,在该文件中您将使用[::-1]切片来写入或附加变量,从而完全反转文件。您还可以使用readlines()使其成为一行列表,您可以对其进行操作

def copy_and_reverse(filename, newfile):
    with open(filename) as file:
        text = file.read()
    with open(newfile, "w") as file2:
        file2.write(text[::-1])

0

大多数答案都需要在执行任何操作之前先读取整个文件。此样本从头开始读取越来越大的样本

在编写此答案时,我仅看到MuratYükselen的答案。几乎一样,我认为这是一件好事。下面的示例还处理\ r,并在每个步骤中增加其缓冲区大小。我也有一些单元测试来备份此代码。

def readlines_reversed(f):
    """ Iterate over the lines in a file in reverse. The file must be
    open in 'rb' mode. Yields the lines unencoded (as bytes), including the
    newline character. Produces the same result as readlines, but reversed.
    If this is used to reverse the line in a file twice, the result is
    exactly the same.
    """
    head = b""
    f.seek(0, 2)
    t = f.tell()
    buffersize, maxbuffersize = 64, 4096
    while True:
        if t <= 0:
            break
        # Read next block
        buffersize = min(buffersize * 2, maxbuffersize)
        tprev = t
        t = max(0, t - buffersize)
        f.seek(t)
        lines = f.read(tprev - t).splitlines(True)
        # Align to line breaks
        if not lines[-1].endswith((b"\n", b"\r")):
            lines[-1] += head  # current tail is previous head
        elif head == b"\n" and lines[-1].endswith(b"\r"):
            lines[-1] += head  # Keep \r\n together
        elif head:
            lines.append(head)
        head = lines.pop(0)  # can be '\n' (ok)
        # Iterate over current block in reverse
        for line in reversed(lines):
            yield line
    if head:
        yield head

0

逐行读取文件,然后以相反顺序将其添加到列表中。

这是代码示例:

reverse = []
with open("file.txt", "r") as file:
    for line in file:
        line = line.strip()
         reverse[0:0] = line

这似乎是已接受答案中解决方案的劣等版本。
AMC


0
def previous_line(self, opened_file):
        opened_file.seek(0, os.SEEK_END)
        position = opened_file.tell()
        buffer = bytearray()
        while position >= 0:
            opened_file.seek(position)
            position -= 1
            new_byte = opened_file.read(1)
            if new_byte == self.NEW_LINE:
                parsed_string = buffer.decode()
                yield parsed_string
                buffer = bytearray()
            elif new_byte == self.EMPTY_BYTE:
                continue
            else:
                new_byte_array = bytearray(new_byte)
                new_byte_array.extend(buffer)
                buffer = new_byte_array
        yield None

使用:

opened_file = open(filepath, "rb")
iterator = self.previous_line(opened_file)
line = next(iterator) #one step
close(opened_file)

-3

我不得不在一段时间前使用以下代码。它通过管道传递给外壳。恐怕我没有完整的脚本了。如果您使用的是unixish操作系统,则可以使用“ tac”,但是,例如在Mac OSX上,tac命令不起作用,请使用tail -r。以下代码段测试了您所使用的平台,并相应地调整了命令

# We need a command to reverse the line order of the file. On Linux this
# is 'tac', on OSX it is 'tail -r'
# 'tac' is not supported on osx, 'tail -r' is not supported on linux.

if sys.platform == "darwin":
    command += "|tail -r"
elif sys.platform == "linux2":
    command += "|tac"
else:
    raise EnvironmentError('Platform %s not supported' % sys.platform)

海报正在寻找一个python答案。
mikemaccana

好吧,这是一个Python答案,尽管它似乎并不完整。
DrDee 2011年

2
它不是=未,不跨平台,使用系统命令Python化
叫Phyo Arkar伦

张贴者正在寻找“使用python”的答案,该答案确实是编写的。但是我同意,与发布的许多其他解决方案相比,这不是一个很好的解决方案。
jeorgen

1
该代码段不够完整,无法评估其正确性(未显示调用的其他部分),但是将Shell命令存储在字符串中本身就很值得怀疑-除非有大量操作,否则很容易出现Shell注入错误。的照顾。
查尔斯·达菲
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.