2011-04-25 13 views
16

यही वह है जो मैंने अभी तक किया है। क्या यह सब आपको चाहिए? मैं त्रुटि मिलती रहती है "त्रुटि: अनबाउंड मॉड्यूल कक्षा"ओकैमल में टेक्स्ट फ़ाइल से लाइनों में मैं कैसे पढ़ूं?

let r file = 
    let chan = open_in file in 
    Std.input_list (chan) 

उत्तर

17

आप Extlib स्थापित (और जाहिरा तौर पर आप ऊपर त्रुटि संदेश के आधार पर नहीं है) की जरूरत नहीं है, तो आम तौर पर यह कुछ इस तरह किया जाता है:

let read_file filename = 
let lines = ref [] in 
let chan = open_in filename in 
try 
    while true; do 
    lines := input_line chan :: !lines 
    done; !lines 
with End_of_file -> 
    close_in chan; 
    List.rev !lines ;; 

आप Extlib की क्या ज़रूरत है, तो:

let read_file filename = 
    let chan = open_in filename in 
    Std.input_list chan 

... जो काफी तुम्हारे पास क्या है है।

आप Batteries-included पुस्तकालय आप एक Enum.t में एक फ़ाइल पढ़ सकते हैं और इस पर पुनरावृति इस प्रकार कर सकता है, तो:

let filelines = File.lines_of filename in 
Enum.iter (fun line -> (*Do something with line here*)) filelines 
+0

बहुत बहुत धन्यवाद! – Travis

+2

extlib संस्करण में fd leak का पता चला: इनपुट चैनल बंद नहीं है – ygrek

+0

क्या आप समझा सकते हैं कि आप खाली सूची के साथ थोड़ी देर लूप क्यों कर रहे हैं? मुझे लगता है कि यह कभी नहीं पहुंचा। – Rizo

0

Std.input_list जाहिरा तौर पर Extlib की आवश्यकता है, जो आप अपने सिस्टम (libextlib-ocaml और libextlib-ocaml-dev पर स्थापित करना चाहिए डेबियन सिस्टम पर)।

let read_all_lines file_name = 
    let in_channel = open_in file_name in 
    let rec read_recursive lines = 
    try 
     Scanf.fscanf in_channel "%[^\r\n]\n" (fun x -> read_recursive (x :: lines)) 
    with 
     End_of_file -> 
     lines in 
    let lines = read_recursive [] in 
    let _ = close_in_noerr in_channel in 
    List.rev (lines);; 

उपयोग::

let make_reader file_name = 
    let in_channel = open_in file_name in 
    let closed = ref false in 
    let read_next_line = fun() -> 
    if !closed then 
     None 
    else 
     try 
     Some (Scanf.fscanf in_channel "%[^\r\n]\n" (fun x -> x)) 
     with 
     End_of_file -> 
      let _ = close_in_noerr in_channel in 
      let _ = closed := true in 
      None in 
    read_next_line;; 

:

let all_lines = read_all_lines "input.txt";; 

हालांकि, मैं पंक्ति-दर-पंक्ति स्ट्रीम करने के लिए पसंद करते हैं

1

यहाँ एक पुनरावर्ती समाधान scanf का उपयोग कर उपयोग:

let read_next = make_reader "input.txt";; 
let next_line = read_next();; 

और टुकड़े का एक सा हो सकता है:

type reader = {read_next : unit -> string option};; 

let make_reader file_name = 
    let in_channel = open_in file_name in 
    let closed = ref false in 
    let read_next_line = fun() -> 
    if !closed then 
     None 
    else 
     try 
     Some (Scanf.fscanf in_channel "%[^\r\n]\n" (fun x -> x)) 
     with 
     End_of_file -> 
      let _ = close_in_noerr in_channel in 
      let _ = closed := true in 
      None in 
    {read_next = read_next_line};; 

उपयोग:

let r = make_reader "input.txt";; 
let next_line = r.read_next();; 

आशा इस मदद करता है!

+0

[http://caml.inria.fr/pub/docs/manual-ocaml/libref/Scanf.html#space ](http://caml.inria.fr/pub/docs/manual-ocaml/libref/Scanf .html # space) _ ** ... इसी तरह, प्रारूप स्ट्रिंग में एक लाइन फीड कैरेक्टर या तो एक लाइन फीड या कैरिज रिटर्न से मेल खाता है, उसके बाद लाइन फीड ** _ तो, यह समाधान "चाहिए" दोनों "\ r \ n" और "\ n" स्टाइल लाइन समाप्ति के लिए काम करें (केवल लिनक्स सिस्टम पर परीक्षण किया गया है)। –

+0

सभी कोड स्निपेट इनपुट चैनल बंद नहीं करते हैं, इसलिए लीक फ़ाइल डिस्क्रिप्टर – ygrek

+0

@ygrek: धन्यवाद! फिक्स्ड। हो सकता है कि कॉलिंग पार्टी को उद्घाटन/समापन व्यवसाय करने दें और इन कार्यों के बजाय इनपुट चैनल ले जाएं। –

0

स्कैनफ "स्ट्रिंग इंडिकेशन" और शून्य-चौड़ाई वाले वर्ण का उपयोग करके फ़ाइल से लाइनों को पढ़ने के लिए एक और शैली। यह पारंपरिक अनिवार्य शैली की तरह है।

open Scanf 
open Printf 

(* little helper functions *) 
let id x = x 
let const x = fun _ -> x 
let read_line file = fscanf file "%[email protected]\n" id 
let is_eof file = try fscanf file "%0c" (const false) with End_of_file -> true 

let _ = 
    let file = open_in "/path/to/file" in 

    while not (is_eof file) do 
    let s = read_line file in 
    (* do something with s *) 
    printf "%s\n" s 
    done; 

    close_in file 

नोट:

  1. read_line उपेक्षा एक अनुगामी \ N है, इसलिए यदि आपकी फ़ाइल का अंतिम वर्ण \ n है, यह हो सकता है लगता है कि आपके पिछले खाली पंक्ति छूट गई है।
  2. स्कैनफ का उपयोग करते समय, बफरकरण के कारण, उसी चैनल पर अन्य निम्न स्तर के पढ़ने को मिश्रित न करें, अन्यथा इसका अजीब व्यवहार होगा।
15

आप OCaml कोर पुस्तकालय स्थापित है, तो यह उतना ही आसान है के रूप में:

open Core.Std 
let r file = In_channel.read_lines file 

आप corebuild स्थापित किया है, तो आप सिर्फ अपने कोड इसके साथ संकलन कर सकते हैं:

corebuild filename.byte 

यदि आपका कोड filename.ml नाम की फ़ाइल में रहता है।

यदि आपके पास ओकैमल कोर नहीं है, या इसे स्थापित नहीं करना चाहते हैं, या कुछ अन्य मानक लाइब्रेरी कार्यान्वयन, तो निश्चित रूप से, आप इसे वेनिला ओकैमल की मानक लाइब्रेरी का उपयोग करके कार्यान्वित कर सकते हैं। एक input_line है, जिसे Pervasives मॉड्यूल में परिभाषित किया गया है, जो स्वचालित रूप से सभी ओकैम प्रोग्राम में खोला जाता है (यानी इसकी सभी परिभाषाएं मॉड्यूल नाम के साथ और स्पष्टीकरण के बिना सुलभ होती हैं)। यह फ़ंक्शन in_channel प्रकार का मान स्वीकार करता है और एक लाइन देता है, जिसे चैनल से पढ़ा जाता था। इस समारोह का उपयोग करके आप आवश्यक समारोह को लागू कर सकते हैं:

let read_lines name : string list = 
    let ic = open_in name in 
    let try_read() = 
    try Some (input_line ic) with End_of_file -> None in 
    let rec loop acc = match try_read() with 
    | Some s -> loop (s :: acc) 
    | None -> close_in ic; List.rev acc in 
    loop [] 

इस कार्यान्वयन प्रत्यावर्तन का उपयोग करता है, और भी बहुत कुछ OCaml प्रोग्रामिंग के लिए स्वाभाविक है।

+0

पुनरावर्ती कार्यान्वयन के लिए धन्यवाद! मुझे लूप [] 'में List.rev acc को छोड़कर आपके अधिकांश कोड को समझना प्रतीत होता है। क्या आप कृपया बता सकते हैं कि क्या हो रहा है? सूची में – nambvarun

+1

डेटा प्रीपेड हैं, इसलिए वास्तव में हम 'एसीसी' को स्टैक के रूप में सोच सकते हैं। जब हम लूप खत्म करते हैं (यानी, स्टॉप हालत को दबाएं) हम अपने ढेर को उलट देते हैं, ताकि हमारा फ़ंक्शन सामान्य क्रम में डेटा लौटाए – ivg

1

इस फ़ाइल की लाइनों को पढ़ता है और उनमें से प्रत्येक प्रिंट:

open Core.Std 

let handle_line line = 
    printf "Your line: %s \n" line 

let() = 
    let file_to_read = "./file_to_read.txt" in 
    let lines = In_channel.read_lines file_to_read in 
     List.iter ~f: handle_line lines 
0

यहाँ एक सरल पुनरावर्ती समाधान है कि लाइनों जमा नहीं करता है या बाहरी पुस्तकालयों का उपयोग है, लेकिन आप एक पंक्ति, इस प्रक्रिया में यह एक का उपयोग कर पढ़ने देता कार्य करें, पूरा होने तक अगले पुनरावर्ती पढ़ें, फिर साफ से बाहर निकलें। बाहर निकलने का कार्य खुले फ़ाइलहेडल को बंद करता है और कॉलिंग प्रोग्राम में सफलता का संकेत देता है।

let read_lines file process = 
    let in_ch = open_in file in 
    let rec read_line() = 
    let line = try input_line in_ch with End_of_file -> exit 0 
    in (* process line in this block, then read the next line *) 
     process line; 
     read_line(); 
in read_line();; 

read_lines some_file print_endline;; 
संबंधित मुद्दे