2009-07-07 10 views
6

Jestem całkiem nowy w programowaniu, więc bądź delikatny. Próbuję wyodrębnić numery IBSN z pliku .dat bazy danych biblioteki. Napisałem kod, który działa, ale przeszukuje tylko około połowy pliku 180 MB. Jak mogę go dostosować, aby przeszukać cały plik? Albo jak mogę napisać program, który podzieli plik danych na porcje?Jak obsługiwać duże pliki w Ruby?

edit: Oto mój kod:

export = File.new("resultsfinal.txt","w+") 

File.open("bibrec2.dat").each do |line| 
    line.scan(/[a]{1}[1234567890xX]{10}\W/) do |x| 
    export.puts x 
    end 
    line.scan(/[a]{1}[1234567890xX]{13}/) do |x| 
    export.puts x 
    end 
end 
+0

@ zed_0xff: Podejście Yoanna Le Touche nie odczytało całego pliku do pamięci. –

Odpowiedz

-2

Jeśli programowanie na nowoczesnym systemie operacyjnym, a komputer ma wystarczającą ilość pamięci (powiedzieć 512megs), Ruby nie powinien mieć czytania całego pliku do pamięci problemu .

Rzeczy zwykle stają się niepewne, gdy dojdziemy do około 2 gigabajtowego zestawu roboczego na typowym 32-bitowym systemie operacyjnym.

+0

Cóż, mój robi się niepewny z 4GB na Vista, jeśli to pomaga. Ponadto nie powoduje błędu, tylko niepełny zestaw wyników. –

+0

Wierzę, że on oznacza, że ​​dane to 4 GB, a nie rozmiar twojej pamięci. 32-bitowe systemy operacyjne nie mogą obsłużyć więcej niż około 3,5 GB pamięci RAM, więc nie masz do dyspozycji 4 GB pamięci RAM, niezależnie od tego (chyba, że ​​korzystasz z 64-bitowej wersji systemu Vista). Jeśli twój zbiór danych to tylko 180 MB, problem musi znajdować się w kodzie. Czy opublikujesz scenariusz? – jkeys

+0

Nie ma problemu, opublikuję go jutro. Dziękuję bardzo. –

1

Co do problemu z wydajnością, nie widzę niczego szczególnie martwiącego się o rozmiar pliku: 180 MB nie powinno stanowić problemu. Co dzieje się z używaniem pamięci podczas uruchamiania skryptu?

Nie jestem jednak pewien, czy Twoje Wyrażenia Regularne robią, co chcesz. To, na przykład:

/[a]{1}[1234567890xX]{10}\W/ 

ma (chyba) to:

  • jedno "a". Czy naprawdę chcesz dopasować do "a"? wystarczyłoby "a", a nie "[a] {1}" w tym przypadku.
  • dokładnie 10 (cyfra lub "X" lub "X")
  • pojedynczy "non-słowo" charakter tzn nie az, AZ, 0-9 lub podkreślenia

Istnieje kilka Próbki ISBN matchers here i here, chociaż wydają się pasować do czegoś bardziej podobnego do formatu, który widzimy na tylnej okładce książki i domyślam się, że twój plik wejściowy usunął niektóre z tego formatowania.

+0

Tak, oryginalny plik danych sformatował numery ISBN, aby były w tym formacie. Nie mam pojęcia, dlaczego tak się stało! Dobre wołanie o samo pisanie "a" wydaje się dużo prostsze. –

4

Powinieneś spróbować przechwycić wyjątek, aby sprawdzić, czy problem rzeczywiście dotyczy bloku odczytu, czy nie.

Tak, więc wiesz, że już napisałem skrypt z taką samą składnią, aby wyszukać prawdziwy duży plik ~ 8 GB bez problemu.

export = File.new("resultsfinal.txt","w+") 

File.open("bibrec2.dat").each do |line| 
    begin 
    line.scan(/[a]{1}[1234567890xX]{10}\W/) do |x| 
     export.puts x 
    end 
    line.scan(/[a]{1}[1234567890xX]{13}/) do |x| 
     export.puts x 
    end 
    rescue 
    puts "Problem while adding the result" 
    end 
end 
2
file = File.new("bibrec2.dat", "r") 
while (line = file.gets) 
    line.scan(/[a]{1}[1234567890xX]{10}\W/) do |x| 
    export.puts x 
    end 
    line.scan(/[a]{1}[1234567890xX]{13}/) do |x| 
    export.puts x 
    end 
end 
file.close 
3

Najważniejsze jest to, aby oczyścić i połączyć regex dla korzyści wydajności. Powinieneś także zawsze używać składni bloków z plikami, aby upewnić się, że fd są poprawnie zamykane. Plik nr każde nie wczytać cały plik do pamięci, to nie jeden wiersz na raz:

File.open("resultsfinal.txt","w+") do |output| 
    File.open("bibrec2.dat").each do |line| 
     output.puts line.scan(/a[\dxX]{10}(?:[\dxX]{3}|\W)/) 
    end 
end 
1

Możesz zajrzeć do korzystania File#truncate i IO#seek i stosują algorytm wyszukiwania binarnego typu. #truncate może być destrukcyjny, więc powinieneś zduplikować plik (wiem, że to kłopot).

middle = File.new("my_huge_file.dat").size/2 
tmpfile = File.new("my_huge_file.dat", "r+").truncate(middle) 
# run search algoritm on 'tmpfile' 
File.open("my_huge_file.dat") do |huge_file| 
    huge_file.seek(middle + 1) 
    # run search algorithm from here 
end 

Kod jest wysoce nieprzetestowany, kruchy i niekompletny. Ale mam nadzieję, że da ci to platformę do budowania.

+0

co, jeśli podzielisz plik w środku linii? ;) – fenec

Powiązane problemy