Como assisto a um arquivo para alterações?


323

Eu tenho um arquivo de log sendo gravado por outro processo que desejo observar nas alterações. Cada vez que ocorre uma alteração, eu gostaria de ler os novos dados para fazer algum processamento.

Qual é a melhor forma de fazer isso? Eu esperava que houvesse algum tipo de gancho na biblioteca do PyWin32. Eu encontrei a win32file.FindNextChangeNotificationfunção, mas não tenho idéia de como pedir para assistir a um arquivo específico.

Se alguém fez algo assim, ficaria muito grato em saber como ...

[Editar] Eu deveria ter mencionado que estava atrás de uma solução que não requer pesquisa.

[Editar] Maldições! Parece que isso não funciona em uma unidade de rede mapeada. Acho que o Windows não 'escuta' nenhuma atualização do arquivo da mesma forma que em um disco local.


1
no Linux pode-se usar chamadas de stracemonitoramento writepara isso
test30 30/03

A resposta do @ simao usa python-watchdog. O Python-Watchdog possui ótima documentação -> aqui está um link para a documentação ["QuickStart"], que fornece um exemplo de código mínimo que observa o diretório de trabalho atual.
Trevor Boyd Smith

Respostas:


79

Você já consultou a documentação disponível em http://timgolden.me.uk/python/win32_how_do_i/watch_directory_for_changes.html ? Se você só precisa trabalhar no Windows, o segundo exemplo parece ser exatamente o que você deseja (se você trocar o caminho do diretório pelo do arquivo que deseja assistir).

Caso contrário, a pesquisa provavelmente será a única opção realmente independente de plataforma.

Nota: Eu não tentei nenhuma dessas soluções.


5
Esta resposta é específica do Windows, mas parece que algumas soluções de plataforma cruzada para esse problema foram postadas aqui também.
Anderson Green

Existe uma referência, se esse processo for mais lento, implementá-lo em uma linguagem nativa como c ++?
precisa saber é o seguinte

É melhor inserir o conteúdo relevante das fontes citadas, pois elas podem ficar desatualizadas.
Trilarion

2
(1.) no final desta resposta, há um forte aviso de isenção de responsabilidade ... "Não tentei nenhuma dessas soluções". (2.) esta resposta é mais ou menos uma resposta "somente link" (3.) a resposta menciona "pesquisa", mas não fornece nada útil depois disso ... onde a resposta do @ Deestan fornece algumas informações boas sobre pesquisa
Trevor Boyd Smith

283

Você tentou usar o Watchdog ?

Biblioteca de API Python e utilitários de shell para monitorar eventos do sistema de arquivos.

O monitoramento de diretório ficou fácil com

  • Uma API de plataforma cruzada.
  • Uma ferramenta de shell para executar comandos em resposta a alterações de diretório.

Comece rapidamente com um exemplo simples no Início Rápido ...


56
Instalável com easy_install? Verifica. Licença gratuita? Verifique . Resolve o problema nas grandes plataformas? Verifique . Eu apoio esta resposta. Nota: o exemplo na página do projeto não funciona imediatamente. Use aquele no github deles .
Inaimathi 22/10/12

6
Usamos cão de guarda. Podemos mudar para QFileSystemWatcher. Apenas um cão de guarda de alerta justo é bom, mas longe de ser perfeito em todas as plataformas (no momento). Cada sistema operacional possui suas idiossincrasias. Portanto, a menos que você se dedique a torná-lo perfeito, estará arrancando os cabelos. Se você está olhando apenas para assistir a 10 arquivos, eu faria uma pesquisa. O cache do disco do sistema operacional é muito maduro e o Watchdog envolve APIs de pesquisa de qualquer maneira. É principalmente para assistir a enormes estruturas de pastas IMHO.
SilentSteel 15/10

3
Minha única queixa com o cão de guarda é que ele tem muitas dependências. Menos que o PyQt, é claro, mas ele não funciona e parece a solução mínima e melhor prática, a solução "faça um trabalho e faça o que é certo".
precisa saber é o seguinte

1
@Denfromufa está correto aqui? O watchdog realmente bloqueia os arquivos, para que não possam ser editados simultaneamente para observá-los? Mal posso acreditar nisso, seria completamente inútil.
Michel Müller

1
@ MichelMüller Acabei de verificar este exemplo (veja o link abaixo) e funciona! não tenho certeza do que estava errado antes, mas esta resposta não fornece nenhum exemplo. stackoverflow.com/a/18599427/2230844
denfromufa

92

Se a pesquisa for boa o suficiente para você, eu apenas observaria se o status do arquivo "horário modificado" muda. Para ler:

os.stat(filename).st_mtime

(Observe também que a solução de eventos de alteração nativa do Windows não funciona em todas as circunstâncias, por exemplo, em unidades de rede.)

import os

class Monkey(object):
    def __init__(self):
        self._cached_stamp = 0
        self.filename = '/path/to/file'

    def ook(self):
        stamp = os.stat(self.filename).st_mtime
        if stamp != self._cached_stamp:
            self._cached_stamp = stamp
            # File has changed, so do something...

1
Como você pode fazer isso em um intervalo?
Dopatraman

1
@dopatraman Aqui está como você pode fazer isso em um intervalo `import sys import time de publicação = Monkey () enquanto True: try: time.sleep (1) pub.watch () exceto KeyboardInterrupt: print ('\ nDone') break exceto : print (f'Unhandled error: {sys.exc_info () [0]} ') `
Vlad Bezden

Ótima solução simples! Eu adicionei um cheque para mantê-lo de relatar o arquivo alterado na primeira execução: if self._cached_stamp is not None.
Noumenon 27/02

50

Se você deseja uma solução multiplataforma, verifique QFileSystemWatcher . Aqui está um código de exemplo (não higienizado):

from PyQt4 import QtCore

@QtCore.pyqtSlot(str)
def directory_changed(path):
    print('Directory Changed!!!')

@QtCore.pyqtSlot(str)
def file_changed(path):
    print('File Changed!!!')

fs_watcher = QtCore.QFileSystemWatcher(['/path/to/files_1', '/path/to/files_2', '/path/to/files_3'])

fs_watcher.connect(fs_watcher, QtCore.SIGNAL('directoryChanged(QString)'), directory_changed)
fs_watcher.connect(fs_watcher, QtCore.SIGNAL('fileChanged(QString)'), file_changed)

6
Eu acho que essa é possivelmente a melhor resposta do grupo, pois eles: a) confiam no objeto FileSystemwatcher do Win32 e não podem ser portados; É uma pena que o Python não tenha esse recurso embutido, pois o PyQt é uma enorme dependência se tudo o que você está usando é a classe QFileSystemWatcher.
CadentOrange

4
Eu gosto desta solução. Queria ressaltar que você precisará de uma instância do QApplication para que funcione. Adicionei "app = QtGui.QApplication (sys.argv)" logo abaixo das importações e depois "app.exec_ ()" após as conexões do sinal.
Spencewah

Apenas testando isso em uma caixa Linux, estou vendo que o método directory_changed está sendo chamado, mas não o file_changed.
Ken Kinder

@CadentOrange, se você não gosta da dependência PyQt, o watchdogpacote é a resposta certa
Mike Pennington

por que não usar PySidepara isso em vez de PyQtpara um uso tão pequeno.
Ciasto piekarz 16/09

29

Ele não deve funcionar no Windows (talvez com o cygwin?), Mas para o usuário unix, você deve usar a chamada de sistema "fcntl". Aqui está um exemplo em Python. É basicamente o mesmo código se você precisar escrevê-lo em C (mesmos nomes de função)

import time
import fcntl
import os
import signal

FNAME = "/HOME/TOTO/FILETOWATCH"

def handler(signum, frame):
    print "File %s modified" % (FNAME,)

signal.signal(signal.SIGIO, handler)
fd = os.open(FNAME,  os.O_RDONLY)
fcntl.fcntl(fd, fcntl.F_SETSIG, 0)
fcntl.fcntl(fd, fcntl.F_NOTIFY,
            fcntl.DN_MODIFY | fcntl.DN_CREATE | fcntl.DN_MULTISHOT)

while True:
    time.sleep(10000)

3
Funciona como um encanto com o kernel Linux 2.6.31 em um sistema de arquivos ext4 (no Ubuntu 10.04), embora apenas para diretórios - gera um IOError "não um diretório" se eu o usar com um arquivo.
David Underhill

1
ÓTIMO! O mesmo para mim, funciona apenas para o diretório e assiste os arquivos nesse diretório. Mas não funcionará para arquivos modificados em subdiretórios, portanto, parece que você precisa percorrer os subdiretórios e assistir a todos eles. (ou se existe uma maneira melhor de fazer isso?)
lfagundes

20

Confira pyinotify .

O inotify substitui o dnotify (de uma resposta anterior) em linuxes mais recentes e permite o monitoramento no nível do arquivo e não no nível do diretório.


5
Para não atrapalhar esta resposta, mas depois de ler este artigo, eu diria que pode não ser uma solução tão charmosa quanto se pensava. serpentine.com/blog/2008/01/04/why-you-should-not-use-pyinotify
NuclearPeon

1
O pyinotify tem muitas desvantagens, começando da base de código muito não sintônica ao consumo de memória. Melhor olhar para outras opções ..
Tyto

13

Bem, depois de um pouco de hacking no script de Tim Golden, tenho o seguinte, que parece funcionar muito bem:

import os

import win32file
import win32con

path_to_watch = "." # look at the current directory
file_to_watch = "test.txt" # look for changes to a file called test.txt

def ProcessNewData( newData ):
    print "Text added: %s"%newData

# Set up the bits we'll need for output
ACTIONS = {
  1 : "Created",
  2 : "Deleted",
  3 : "Updated",
  4 : "Renamed from something",
  5 : "Renamed to something"
}
FILE_LIST_DIRECTORY = 0x0001
hDir = win32file.CreateFile (
  path_to_watch,
  FILE_LIST_DIRECTORY,
  win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE,
  None,
  win32con.OPEN_EXISTING,
  win32con.FILE_FLAG_BACKUP_SEMANTICS,
  None
)

# Open the file we're interested in
a = open(file_to_watch, "r")

# Throw away any exising log data
a.read()

# Wait for new data and call ProcessNewData for each new chunk that's written
while 1:
  # Wait for a change to occur
  results = win32file.ReadDirectoryChangesW (
    hDir,
    1024,
    False,
    win32con.FILE_NOTIFY_CHANGE_LAST_WRITE,
    None,
    None
  )

  # For each change, check to see if it's updating the file we're interested in
  for action, file in results:
    full_filename = os.path.join (path_to_watch, file)
    #print file, ACTIONS.get (action, "Unknown")
    if file == file_to_watch:
        newText = a.read()
        if newText != "":
            ProcessNewData( newText )

Provavelmente, isso poderia resultar em uma verificação de erro muito maior, mas, simplesmente observando um arquivo de log e processando-o antes de enviá-lo para a tela, isso funciona bem.

Obrigado a todos por sua contribuição - ótimas coisas!


10

Para assistir a um único arquivo com sondagens e dependências mínimas, eis um exemplo completo, com base na resposta do Deestan (acima):

import os
import sys 
import time

class Watcher(object):
    running = True
    refresh_delay_secs = 1

    # Constructor
    def __init__(self, watch_file, call_func_on_change=None, *args, **kwargs):
        self._cached_stamp = 0
        self.filename = watch_file
        self.call_func_on_change = call_func_on_change
        self.args = args
        self.kwargs = kwargs

    # Look for changes
    def look(self):
        stamp = os.stat(self.filename).st_mtime
        if stamp != self._cached_stamp:
            self._cached_stamp = stamp
            # File has changed, so do something...
            print('File changed')
            if self.call_func_on_change is not None:
                self.call_func_on_change(*self.args, **self.kwargs)

    # Keep watching in a loop        
    def watch(self):
        while self.running: 
            try: 
                # Look for changes
                time.sleep(self.refresh_delay_secs) 
                self.look() 
            except KeyboardInterrupt: 
                print('\nDone') 
                break 
            except FileNotFoundError:
                # Action on file not found
                pass
            except: 
                print('Unhandled error: %s' % sys.exc_info()[0])

# Call this function each time a change happens
def custom_action(text):
    print(text)

watch_file = 'my_file.txt'

# watcher = Watcher(watch_file)  # simple
watcher = Watcher(watch_file, custom_action, text='yes, changed')  # also call custom action function
watcher.watch()  # start the watch going

2
Você pode criar watch_filee _cached_stampentrar em listas e iterá-las em um loop for. Realmente não escala bem para um grande número de arquivos embora
4Oh4

Isso não aciona a ação toda vez que é executada? _cached_stamp é definido como 0 e, em seguida, comparado com os.stat (self.filename) .st_mtime. _cached_stamp deve ser definido como os.stat (self.filename) .st_mtime no construtor, não?
Seanonymous 16/08/19

1
call_func_on_change()será acionado na primeira execução de look(), mas _cached_stampserá atualizado, portanto, não será acionado novamente até que o valor das os.stat(self.filename).st_mtime. _cached_stampalterações seja alterado.
4Oh4 18/08/19

1
Você poderia definir o valor _cached_stampno construtor se você não quer call_func_on_change()ser chamado na primeira execução
4Oh4

Eu usei seu script para chamar alguma função na alteração de arquivo. Minha função não aceita argumentos diferentes dos seus. Eu pensei que, para fazê-lo funcionar, eu preciso remover * args, ** kwargs. Parecia que (coloquei apenas linhas com alterações): self.call_func_on_change(self) def custom_action(): watcher = Watcher(watch_file, custom_action())Mas isso não funcionou. A ação foi chamada apenas durante a primeira iteração: Arquivo alterado sim, alterado Arquivo alterado Arquivo alterado Arquivo alterado Ele começou a funcionar quando mantive * args e o chamei: watcher = Watcher(watch_file, custom_action)luto para me perguntar por que?
zwornik 01/04

7

Verifique minha resposta para uma pergunta semelhante . Você pode tentar o mesmo loop no Python. Esta página sugere:

import time

while 1:
    where = file.tell()
    line = file.readline()
    if not line:
        time.sleep(1)
        file.seek(where)
    else:
        print line, # already has newline

Veja também a pergunta tail () um arquivo com Python .


Você pode sys.stdout.write (linha). Seu código não funciona se o arquivo estiver truncado. Python possui arquivo de função embutido ().
JFS

Publiquei uma versão modificada do seu código. Você pode incorporá-lo na sua resposta, se funcionar para você.
JFS

7

A solução mais simples para mim é usar a ferramenta watchdog, watchmedo

Em https://pypi.python.org/pypi/watchdog , agora tenho um processo que consulta os arquivos sql em um diretório e os executa, se necessário.

watchmedo shell-command \
--patterns="*.sql" \
--recursive \
--command='~/Desktop/load_files_into_mysql_database.sh' \
.

6

Bem, como você está usando Python, você pode simplesmente abrir um arquivo e continuar lendo as linhas dele.

f = open('file.log')

Se a linha lida não estiver vazia , você a processa.

line = f.readline()
if line:
    // Do what you want with the line

Pode estar faltando que não há problema em continuar ligando readlinepara o EOF. Apenas retornará uma string vazia neste caso. E quando algo é anexado ao arquivo de log, a leitura continuará de onde parou, conforme necessário.

Se você estiver procurando por uma solução que use eventos ou uma biblioteca específica, especifique isso na sua pergunta. Caso contrário, acho que esta solução está bem.


6

Aqui está uma versão simplificada do código do Kender que parece fazer o mesmo truque e não importa o arquivo inteiro:

# Check file for new data.

import time

f = open(r'c:\temp\test.txt', 'r')

while True:

    line = f.readline()
    if not line:
        time.sleep(1)
        print 'Nothing New'
    else:
        print 'Call Function: ', line

6

Essa é outra modificação do script de Tim Goldan, que roda em tipos unix e adiciona um observador simples para modificação de arquivo usando um dict (file => time).

use: WhateverName.py caminho_para_dir_para_watch

#!/usr/bin/env python

import os, sys, time

def files_to_timestamp(path):
    files = [os.path.join(path, f) for f in os.listdir(path)]
    return dict ([(f, os.path.getmtime(f)) for f in files])

if __name__ == "__main__":

    path_to_watch = sys.argv[1]
    print('Watching {}..'.format(path_to_watch))

    before = files_to_timestamp(path_to_watch)

    while 1:
        time.sleep (2)
        after = files_to_timestamp(path_to_watch)

        added = [f for f in after.keys() if not f in before.keys()]
        removed = [f for f in before.keys() if not f in after.keys()]
        modified = []

        for f in before.keys():
            if not f in removed:
                if os.path.getmtime(f) != before.get(f):
                    modified.append(f)

        if added: print('Added: {}'.format(', '.join(added)))
        if removed: print('Removed: {}'.format(', '.join(removed)))
        if modified: print('Modified: {}'.format(', '.join(modified)))

        before = after

Atualizado para suportar python3
ronedg 4/11/19

4

Como você pode ver no artigo de Tim Golden , apontado por Horst Gutmann , o WIN32 é relativamente complexo e observa diretórios, não um único arquivo.

Eu gostaria de sugerir que você analise o IronPython , que é uma implementação em python .NET . Com o IronPython, você pode usar toda a funcionalidade do .NET - incluindo

System.IO.FileSystemWatcher

Que lida com arquivos únicos com uma interface de evento simples .


@ Ciasto, porque é necessário ter o Iron Python disponível, em vez de uma instalação básica do Python.
Jon Cage

1

Este é um exemplo de verificação de alterações em um arquivo. Um que pode não ser a melhor maneira de fazê-lo, mas com certeza é um caminho curto.

Ferramenta útil para reiniciar o aplicativo quando alterações foram feitas na fonte. Eu fiz isso ao jogar com o pygame para que eu possa ver os efeitos imediatamente após o salvamento do arquivo.

Quando usado no pygame, certifique-se de que as coisas no loop 'while' sejam colocadas no loop do jogo, também conhecido como update ou o que for. Caso contrário, seu aplicativo ficará preso em um loop infinito e você não verá o jogo sendo atualizado.

file_size_stored = os.stat('neuron.py').st_size

  while True:
    try:
      file_size_current = os.stat('neuron.py').st_size
      if file_size_stored != file_size_current:
        restart_program()
    except: 
      pass

Caso você queira o código de reinicialização que encontrei na web. Aqui está. (Não é relevante para a pergunta, embora possa ser útil)

def restart_program(): #restart application
    python = sys.executable
    os.execl(python, python, * sys.argv)

Divirta-se fazendo elétrons fazerem o que você quer que eles façam.


Parece que usar em .st_mtimevez de .st_sizeseria mais confiável e uma maneira igualmente curta de fazer isso, embora o OP tenha indicado que ele não queria fazê-lo por meio de pesquisas.
27615

1
ACTIONS = {
  1 : "Created",
  2 : "Deleted",
  3 : "Updated",
  4 : "Renamed from something",
  5 : "Renamed to something"
}
FILE_LIST_DIRECTORY = 0x0001

class myThread (threading.Thread):
    def __init__(self, threadID, fileName, directory, origin):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.fileName = fileName
        self.daemon = True
        self.dir = directory
        self.originalFile = origin
    def run(self):
        startMonitor(self.fileName, self.dir, self.originalFile)

def startMonitor(fileMonitoring,dirPath,originalFile):
    hDir = win32file.CreateFile (
        dirPath,
        FILE_LIST_DIRECTORY,
        win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE,
        None,
        win32con.OPEN_EXISTING,
        win32con.FILE_FLAG_BACKUP_SEMANTICS,
        None
    )
    # Wait for new data and call ProcessNewData for each new chunk that's
    # written
    while 1:
        # Wait for a change to occur
        results = win32file.ReadDirectoryChangesW (
            hDir,
            1024,
            False,
            win32con.FILE_NOTIFY_CHANGE_LAST_WRITE,
            None,
            None
        )
        # For each change, check to see if it's updating the file we're
        # interested in
        for action, file_M in results:
            full_filename = os.path.join (dirPath, file_M)
            #print file, ACTIONS.get (action, "Unknown")
            if len(full_filename) == len(fileMonitoring) and action == 3:
                #copy to main file
                ...

1

Aqui está um exemplo voltado para assistir a arquivos de entrada que gravam não mais que uma linha por segundo, mas geralmente muito menos. O objetivo é anexar a última linha (gravação mais recente) ao arquivo de saída especificado. Copiei isso de um dos meus projetos e apaguei todas as linhas irrelevantes. Você precisará preencher ou alterar os símbolos ausentes.

from PyQt5.QtCore import QFileSystemWatcher, QSettings, QThread
from ui_main_window import Ui_MainWindow   # Qt Creator gen'd 

class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        Ui_MainWindow.__init__(self)
        self._fileWatcher = QFileSystemWatcher()
        self._fileWatcher.fileChanged.connect(self.fileChanged)

    def fileChanged(self, filepath):
        QThread.msleep(300)    # Reqd on some machines, give chance for write to complete
        # ^^ About to test this, may need more sophisticated solution
        with open(filepath) as file:
            lastLine = list(file)[-1]
        destPath = self._filemap[filepath]['dest file']
        with open(destPath, 'a') as out_file:               # a= append
            out_file.writelines([lastLine])

Obviamente, a classe QMainWindow abrangente não é estritamente necessária, ou seja. você pode usar o QFileSystemWatcher sozinho.


0

Você também pode usar uma biblioteca simples chamada repyt , aqui está um exemplo:

repyt ./app.py

0

Parece que ninguém postou fswatch . É um observador de sistema de arquivos multiplataforma. Basta instalar, executar e seguir as instruções.

Eu usei-o com programas python e golang e simplesmente funciona.


0

solução @ 4Oh4 relacionada - uma mudança suave para uma lista de arquivos para assistir;

import os
import sys
import time

class Watcher(object):
    running = True
    refresh_delay_secs = 1

    # Constructor
    def __init__(self, watch_files, call_func_on_change=None, *args, **kwargs):
        self._cached_stamp = 0
        self._cached_stamp_files = {}
        self.filenames = watch_files
        self.call_func_on_change = call_func_on_change
        self.args = args
        self.kwargs = kwargs

    # Look for changes
    def look(self):
        for file in self.filenames:
            stamp = os.stat(file).st_mtime
            if not file in self._cached_stamp_files:
                self._cached_stamp_files[file] = 0
            if stamp != self._cached_stamp_files[file]:
                self._cached_stamp_files[file] = stamp
                # File has changed, so do something...
                file_to_read = open(file, 'r')
                value = file_to_read.read()
                print("value from file", value)
                file_to_read.seek(0)
                if self.call_func_on_change is not None:
                    self.call_func_on_change(*self.args, **self.kwargs)

    # Keep watching in a loop
    def watch(self):
        while self.running:
            try:
                # Look for changes
                time.sleep(self.refresh_delay_secs)
                self.look()
            except KeyboardInterrupt:
                print('\nDone')
                break
            except FileNotFoundError:
                # Action on file not found
                pass
            except Exception as e:
                print(e)
                print('Unhandled error: %s' % sys.exc_info()[0])

# Call this function each time a change happens
def custom_action(text):
    print(text)
    # pass

watch_files = ['/Users/mexekanez/my_file.txt', '/Users/mexekanez/my_file1.txt']

# watcher = Watcher(watch_file)  # simple



if __name__ == "__main__":
    watcher = Watcher(watch_files, custom_action, text='yes, changed')  # also call custom action function
    watcher.watch()  # start the watch going


-2

Não conheço nenhuma função específica do Windows. Você pode tentar obter o hash MD5 do arquivo a cada segundo / minuto / hora (depende da rapidez com que precisa) e compará-lo com o último hash. Quando difere, você sabe que o arquivo foi alterado e você leu as linhas mais recentes.


-6

Eu tentaria algo assim.

    try:
            f = open(filePath)
    except IOError:
            print "No such file: %s" % filePath
            raw_input("Press Enter to close window")
    try:
            lines = f.readlines()
            while True:
                    line = f.readline()
                    try:
                            if not line:
                                    time.sleep(1)
                            else:
                                    functionThatAnalisesTheLine(line)
                    except Exception, e:
                            # handle the exception somehow (for example, log the trace) and raise the same exception again
                            raw_input("Press Enter to close window")
                            raise e
    finally:
            f.close()

O loop verifica se há uma (s) nova (s) linha (s) desde a última vez que o arquivo foi lido - se houver, ele foi lido e passado para a functionThatAnalisesTheLinefunção. Caso contrário, o script aguarda 1 segundo e tenta novamente o processo.


4
-1: Abrir o arquivo e ler linhas não é uma boa idéia quando os arquivos podem ter 100 MB de tamanho. Você teria que executá-lo para todos os arquivos também, o que seria ruim quando você quiser assistir a milhares de arquivos.
Jon gaiola

1
Realmente? Abrindo o arquivo para alterações?
Farsheed 15/09/14
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.