2015-07-21 11 views
5

Rutynowo brakuje mi ostatnich kilku KB pliku, który próbuję skopiować, używając shutil copyfile.Python shutil copyfile - brakujące kilka ostatnich wierszy

Zrobiłem rozeznanie i widzę kogoś z prośbą o coś podobnego tutaj: python shutil copy function missing last few lines

Ale używam CopyFile, który wydaje się nie używać z oświadczeniem ...

with open(src, 'rb') as fsrc: 
    with open(dst, 'wb') as fdst: 
     copyfileobj(fsrc, fdst) 

Więc Jestem zdumiony tym, że więcej użytkowników nie ma tego problemu, jeśli w rzeczywistości jest to pewien rodzaj problemu z buforowaniem - myślę, że byłby bardziej znany.

Wołam CopyFile bardzo prosto, nie sądzę, mógłbym robić coś złego, w zasadzie robi to standardowy sposób myślę:

copyfile(target_file_name,dest_file_name) 

Jednak brakuje mi ostatnią 4KB lub tak z plik za każdym razem.

Nie dotknął również funkcję CopyFile która jest wywoływana w shutil który jest ...

def copyfileobj(fsrc, fdst, length=16*1024): 
    """copy data from file-like object fsrc to file-like object fdst""" 
    while 1: 
     buf = fsrc.read(length) 
     if not buf: 
      break 
     fdst.write(buf) 

Więc jestem ze stratą, ale przypuszczam, że mam zamiar dowiedzieć się czegoś o Flushing, buforowanie, lub z instrukcją, lub ... Pomoc! Dzięki


do Anand: Anand, unikałem wspomnieć, że rzeczy bc to moje poczucie, że nie jest to problem, ale skoro pytasz ... streszczenie jest to, że jestem pobieranie pliku z serwera FTP, sprawdzanie jeśli plik różni się od ostatnio zapisanego egzemplarza, jeśli tak, pobierz plik i zapisz kopię. To okrężny kod spaghetti i został napisany, kiedy, jak sądzę, byłem naprawdę czystym utylitarystycznym nowicjuszem kodera. Wygląda to tak:

for filename in ftp.nlst(filematch): 
    target_file_name = os.path.basename(filename) 
    with open(target_file_name ,'wb') as fhandle: 
    try: 
     ftp.retrbinary('RETR %s' % filename, fhandle.write) 
     the_files.append(target_file_name) 
     mtime = modification_date(target_file_name) 
     mtime_str_for_file = str(mtime)[0:10] + str(mtime)[11:13] + str(mtime)[14:16] + str(mtime)[17:19] + str(mtime)[20:28]#2014-12-11 15:08:00.338415. 
     sorted_xml_files = [file for file in glob.glob(os.path.join('\\\\Storage\\shared\\', '*.xml'))] 
     sorted_xml_files.sort(key=os.path.getmtime) 
     last_file = sorted_xml_files[-1] 
     file_is_the_same = filecmp.cmp(target_file_name, last_file) 
     if not file_is_the_same: 
      print 'File changed!' 
      copyfile(target_file_name, '\\\\Storage\\shared\\'+'datebreaks'+mtime_str_for_file+'.xml') 
     else: 
      print 'File '+ last_file +' hasn\'t changed, doin nothin' 
      continue 
+0

Czy możesz pokazać więcej kodu, jak tworzysz 'target_file_name', a także w jaki sposób sam tworzysz plik target? –

+0

czy istnieje jeden konkretny plik, z którym zawsze się dzieje? o czym jesteś i co python? czy możesz wysłać plik, który zawsze robi to za pomocą? czy próbujesz pisać na dysk sieciowy, czy coś w tym stylu? –

+0

Anand, odpowiedziałem na ciebie w poście, nie byłem pewien, jak to zrobić bc za dużo znaków na komentarz. – 10mjg

Odpowiedz

4

Chodzi tu najprawdopodobniej będzie, że podczas wykonywania line -

ftp.retrbinary('RETR %s' % filename, fhandle.write) 

to używając funkcji fhandle.write() do zapisu danych z serwera FTP do plik (z nazwą - target_file_name), ale do czasu, gdy dzwonisz - shutil.copyfile - bufor dla fhandle nie został całkowicie przepłukany, więc tracisz niektóre dane podczas kopiowania pliku.

Aby się upewnić, że tak się nie dzieje, można albo przenieść logikę copyfile z bloku with dla fhandle.

Możesz też zadzwonić pod numer fhandle.flush(), aby opróżnić bufor przed skopiowaniem pliku.

Uważam, że lepiej zamknąć plik (przenieść logikę z bloku with). Przykład -

for filename in ftp.nlst(filematch): 
    target_file_name = os.path.basename(filename) 
    with open(target_file_name ,'wb') as fhandle: 
     ftp.retrbinary('RETR %s' % filename, fhandle.write) 
    the_files.append(target_file_name) 
    mtime = modification_date(target_file_name) 
    mtime_str_for_file = str(mtime)[0:10] + str(mtime)[11:13] + str(mtime)[14:16] + str(mtime)[17:19] + str(mtime)[20:28]#2014-12-11 15:08:00.338415. 
    sorted_xml_files = [file for file in glob.glob(os.path.join('\\\\Storage\\shared\\', '*.xml'))] 
    sorted_xml_files.sort(key=os.path.getmtime) 
    last_file = sorted_xml_files[-1] 
    file_is_the_same = filecmp.cmp(target_file_name, last_file) 
    if not file_is_the_same: 
     print 'File changed!' 
     copyfile(target_file_name, '\\\\Storage\\shared\\'+'datebreaks'+mtime_str_for_file+'.xml') 
    else: 
     print 'File '+ last_file +' hasn\'t changed, doin nothin' 
     continue 
+0

Dziękuję Anand, ta poprawka była zdecydowanie pierwszą i najbardziej bezpośrednią poprawką dla objawu, który miałem. Rozważę też rozwiązanie nsilent22, które wydaje się bardziej fundamentalne. Wszelkie przemyślenia mile widziane. – 10mjg

+1

nslient22 to to samo rozwiązanie, aby zamknąć plik przed wysłaniem go do funkcji 'copyfile()', przenosząc plik copy (i całą logikę, która nie jest zależna od uchwytu pliku) poza blokiem 'with'. –

+0

Ach, masz rację, skupiłem się na idei "flush" - ale również określiłeś "Aby upewnić się, że to nie nastąpi, możesz albo przenieść logikę copyfile z bloku with for fhandle.". Dziękuję bardzo. – 10mjg

1

This wygląda istnieje lepszy sposób to zrobić zagnieżdżone withs:

with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst: 
     copyfileobj(fsrc, fdst) 

chciałbym spróbować czegoś więcej tak. Jestem daleko od eksperta, mam nadzieję, że ktoś bardziej kompetentny może pomóc w zrozumieniu. Myślę, że wewnętrzne zamknięcie zamyka się przed zewnętrznym.

+0

Byłbym szczęśliwy, aby spróbować/przetestować to. Być może jestem naiwny, ale czy nie jest to dziwne, że ... shutil copyfile może być używany tak szeroko, a jednocześnie być suboptymalny/potrzebować tego rozwiązania? – 10mjg

+0

Tak, to jest dziwne. Będę szczerze mówiąc trochę zaskoczony, jeśli to naprawi, ale "z" blokami zawsze psuje mnie. Używam 'open()' i 'close()' jak noob :) – Will

2

Próbujesz skopiować plik, który nie został zamknięty. Dlatego bufory nie były spłukiwane. Przenieś copyfileobj z bloku with, aby umożliwić zamknięcie fhandle.

Do:

with open(target_file_name ,'wb') as fhandle: 
    ftp.retrbinary('RETR %s' % filename, fhandle.write) 

# and here the rest of your code 
# so fhandle is closed, and file is stored completely on the disk 
+0

Spójrz na to zaraz po tym, jak zakończę testowanie roztworu do płukania Ananda, który złapałem wcześniej, a także zdawałem się go naprawiać. Nie jestem wystarczająco mądry, aby wiedzieć, które rozwiązanie jest lepsze/etc. Twoja wydaje się bardziej podstawowym rozwiązaniem. Dziękujemy i każdy inny wgląd jest doceniany. – 10mjg

+0

To również działa po troszeczkę testów. Wow, tak oczywiste z perspektywy czasu. Dziękuję Ci. – 10mjg

+0

@ 10mjg: Nie ma za co;) – nsilent22

Powiązane problemy