<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # **第 17 章 IO 類** 到目前為止出現的程序中有一些是關于處理文件中的數據的。`IO` 類的主要作用就是讓程序與外部進行數據的輸入(input)/ 輸出(output)操作。在本章中,我們將會討論以下內容。 - **輸入/ 輸出的種類** 介紹 `IO` 類支持的輸入 / 輸出對象。 - **基本的輸入/ 輸出操作** 介紹 `IO` 類的基本操作,以行為單位或者以大小為單位進行讀寫操作。 - **文件指針、二進制模式 / 文本模式、緩沖處理** 深入介紹一些與輸入 / 輸出有關的細節。二進制模式與文本模式是 Windows 特有的規范,若不注意常常會出現問題。 - **與命令進行交互** 介紹與外部命令進行數據交換的方法 ### **17.1 輸入 / 輸出的種類** 我們首先來了解一下輸入 / 輸出的對象到底是什么。 ### **17.1.1 標準輸入 / 輸出** 程序在啟動后會預先分配 3 個 `IO` 對象。 - **標準輸入** 標準輸入可以獲取從鍵盤輸入的內容。通過預定義常量 `STDIN` 可調用操作標準輸入的 `IO` 對象。另外,用全局變量 `$stdin` 也可以引用標準輸入的 `IO` 對象。不指定接收者的 `gets` 方法等都會默認從標準輸入中獲取數據。 - **標準輸出** 向標準輸出寫入的數據會顯示在屏幕中。通過預定義常量 `STDOUT` 可調用操作標準輸出的 `IO` 對象。另外,用全局變量 `$stdout` 也可以引用標準輸出的 `IO` 對象。不指定接收者的 `puts`、`print`、`printf` 等方法會默認將數據寫入到標準輸出。 - **標準錯誤輸出** 向標準錯誤輸出寫入的數據會顯示在屏幕中。通過預定義常量 `STDERR` 可調用操作標準錯誤輸出的 `IO` 對象。另外,用全局變量 `$stderr` 也可以引用標準錯誤輸出的 `IO` 對象。 標準錯誤輸出原本是用于輸出錯誤信息的,但實際上,除輸出警告或者錯誤之外,在希望與程序正常輸出的信息做出區別時也可以使用它(代碼清單 17.1)。 **代碼清單 17.1 out.rb** ~~~ $stdout.print "Output to $stdout.\n" # 標準輸出 $stderr.print "Output to $stderr.\n" # 標準錯誤輸出 ~~~ > **執行示例** ~~~ > ruby out.rb Output to $stdout. Output to $stderr. ~~~ 將輸出結果重定向到文件時,標準輸出的內容會被寫入到文件,只有標準錯誤輸出的內容被 輸出到屏幕中。 > **執行示例** ~~~ > ruby out.rb > log.txt Output to $stderr. ~~~ > **備注** 在執行程序時,在命令后加上 `>` 文件名,就可以將程序執行時的輸出結果保存到文件中。我們把這個控制臺的功能稱為“重定向”。通過這個功能,不僅 ruby 命令,程序的輸出內容也都可以保存在文件中。 根據需要靈活使用標準輸出與標準錯誤輸出,可以使我們很方便地分開獲取正常信息與錯誤信息。 > **備注** ruby 命令的錯誤信息也會被輸出到標準錯誤輸出。 通常標準輸入、標準輸出、標準錯誤輸出都是與控制臺關聯的。但是將命令的輸出重定向到文件,或者使用管道(pipe)將結果傳遞給其他程序時則與控制臺沒有關系。根據實際的使用情況,程序的輸入 / 輸出狀態也各異。`IO` 對象是否與控制臺關聯,我們可以通過 `tty?` 方法判斷。 代碼清單 17.2 是一個檢查標準輸入是否為屏幕的例子。 **代碼清單 17.2 tty.rb** ~~~ if $stdin.tty? print "Stdin is a TTY.\n" else print "Stdin is not a TTY.\n" end ~~~ 下面我們用不同的方式調用這個程序,看看有何不同。首先是普通調用。 > **執行示例** ~~~ > ruby tty.rb Stdin is a TTY. ~~~ 將命令的輸出結果傳給管道,或者通過文件輸入內容時,程序的結果會不一樣。 > **執行示例** ~~~ > echo | ruby tty.rb Stdin is not a TTY. > ruby tty.rb < data.txt Stdin is not a TTY. ~~~ > **備注** TTY 是 TeleTYpe 的縮寫。 ### **17.1.2 文件輸入 / 輸出** 通過 `IO` 類的子類 `File` 類可以進行文件的輸入 / 輸出處理。`File` 類中封裝了文件刪除、文件屬性變更等文件專用的功能,而一些基本的輸入 / 輸出處理則使用繼承自 IO 類的方法。 - ***io*= `File.open`(*file, mode*) *io* = `open`(*file, mode*)** 通過 `File.open` 方法或 `open` 方法打開文件并獲取新的 `IO` 對象。 模式(mode)會指定以何種目的打開文件(表 17.1)。缺省模式為只讀模式(`"r"`)。在 Windows 環境下,在各模式后加上 `b`、通過 `"rb"`、`"rb+"` 等這樣的形式即可表示二進制模式(后述)。 **表 17.1 模式** | 模式 | 意義 | |-----|-----| | `r` | 用只讀模式打開文件。 | | `r+` | 用讀寫模式打開文件。 | | `w` | 用只寫模式打開文件。文件不存在則創建新的文件;文件已存在則清空文件,即將文件大小設置為0。 | | `w+` | 讀寫模式,其余同 `"w"` 。 | | `a` | 用追加模式打開文件。文件不存在則創建新的文件。 | | `a+` | 用讀取/ 追加模式打開文件。文件不存在則創建新的文件。 | - ***io*.`close`** 使用 `close` 方法關閉已打開的文件。 1 個程序中同時打開文件的數量是有限制的,因此使用完的文件應該盡快關閉。如果打開多個文件而不進行關閉操作,程序就很可能會在使用 `open` 方法時突然產生異常。 `File.open` 方法如果使用塊,則文件會在使用完畢后自動關閉。這種情況下,`IO` 對象會被作為塊變量傳遞給塊。塊執行完畢后,塊變量引用的 `IO` 對象也會自動關閉。這種寫法會使輸入 / 輸出的操作范圍更加清晰。 ~~~ File.open("foo.txt") do |io| while line = io.gets ┊ end end ~~~ - ***io*.`close?`** 用 `close?` 方法可以檢查 `IO` 對象是否關閉了。 ~~~ io = File.open("foo.txt") io.close p io.closed? #=> true ~~~ - **`File.read`(*file*)** 使用類方法 `read` 可以一次性讀取文件 `file` 的內容。 ~~~ data = File.read("foo.txt") ~~~ > **備注** 在 Windows 中不能使用 `File.read` 方法讀取像圖像數據等二進制數據。`File.read` 方法使用文本模式打開文件時,會對換行符等進行轉換,因此無法得到正確的結果。詳細內容請參考 17.4 節。 ### **17.2 基本的輸入 / 輸出操作** 輸入 / 輸出操作的數據為字符串,也就是所謂的 `String` 對象。執行輸入操作后,會從頭到尾按順序讀取數據,執行輸出操作后,則會按寫入順序不斷追加數據。 ### **17.2.1 輸入操作** - ***io*.`gets`(*rs*) *io*.`each`(*rs*) *io*.`each_line`(*rs*) *io*.`readlines`(*rs*)** 從 `IO` 類的對象 *io* 中讀取一行數據。用參數 *rs* 的字符串分行。省略 *rs* 時則用預定義變量 `$/`(默認值為 `"\n"`)。 這些方法返回的字符串中包含行末尾的換行符。用 `chmop!` 方法可以很方便地刪除字符串末尾的換行符。 輸入完畢后再嘗試獲取數據時,`gets` 方法會返回 `nil`。另外,我們還可以使用 `eof?` 方法檢查輸入是否已經完畢。 ~~~ while line = io.gets line.chomp! ┊ # 對line 進行的操作 end p io.eof? #=> true ~~~ `while` 條件表達式中同時進行了變量賦值與條件判斷的操作。將 `gets` 方法的返回值復制給 `line`,并將該值作為 `while` 語句的條件來判斷。上面是 `gets` 方法的經典用法,大家應該盡快掌握這種寫法。 用 `each_line` 方法也可以實現同樣的效果。 ~~~ io.each_line do |line| line.chomp! ┊ # 對line 進行的操作 end ~~~ 另外,用 `readlines` 方法可以一次性地讀取所有數據,并返回將每行數據作為元素封裝的數組。 ~~~ ary = io.readlines ary.each_line do |line| line.chomp! ┊ # 對line 進行的操作 end ~~~ > **備注** `gets` 方法與 `puts` 方法,分別是“get string”、“put string”的意思。 - ***io*.`lineno` *io*.`lineno`=(*number*)** 使用 `gets` 方法、`each_line` 方法逐行讀取數據時,會自動記錄讀取的行數。這個行數可以通過 `lineno` 方法取得。此外,通過 `lineno=` 方法也可以改變這個值,但值的改變并不會對文件指針(后述)有影響。 在下面的例子中,逐行讀取標準輸入的數據,并在行首添加行編號。 ~~~ $stdin.each_line do |line| printf("%3d %s", $stdin.lineno, line) end ~~~ - ***io*.`each_char`** 逐個字符地讀取 *io* 中的數據并執行塊。將得到的字符(`String` 對象)作為塊變量傳遞。 ~~~ io.each_char do |ch| ┊ # 對line 進行的操作 end ~~~ - ***io*.`each_byte`** 逐個字節地讀取 *io* 中的數據并啟動塊。將得到的字節所對應的 ASCII 碼以整數值的形式傳遞給塊變量。 - ***io*.`getc`** 只讀取 *io* 中的一個字符。根據文件編碼的不同,有時一個字符會由多個字節組成,但這個方法只會讀取一個字符,然后返回其字符串對象。數據全部讀取完后再讀取時會返回 `nil`。 ~~~ while ch = io.getc ┊ # 對line 進行的操作 end ~~~ - ***io*.`ungetc`(*ch*)** 將參數 *ch* 指定的字符退回到 *io* 的輸入緩沖中。 ~~~ # hello.txt 中的內容為“Hello, Ruby.\n” File.open("hello.txt") do |io| p io.getc #=> "H" io.ungetc(72) p io.gets #=> "Hello, Ruby.\n" end ~~~ 指定一個字符大小的字符串對象。對可退回的字符數沒有限制。 - ***io*.`getbyte`** 只讀取 *io* 中的一個字節,返回得到的字節轉換為 ASCII 碼后的整數對象。數據全部讀取完后再讀取時會返回 `nil`。 - ***io*.`ungetbyte`(*byte*)** 將參數 *byte* 指定的一個字節退回到輸入緩沖中。參數為整數時,將該整數除以 256 后的余數作為 ASCII 碼字符返回一個字節;參數為字符串時,只返回字符串的第一個字節。 - ***io*.`read`(*size*)** 讀取參數 *size* 指定的大小的數據。不指定大小時,則一次性讀取全部數據并返回。 ~~~ # hello.txt 中的內容為"Hello, Ruby.\n" File.open("hello.txt") do |io| p io.read(5) #=> "Hello" p io.read #=> ",Ruby.\n" end ~~~ ### **17.2.2 輸出操作** - ***io*.`puts`(*str0, str1,* …)** 對字符串末尾添加換行符后輸出。指定多個參數時,會分別添加換行符。如果參數為 `Sting` 類以外的對象,則會調用 `to_s` 方法,將其轉換為字符串后再輸出。 **代碼清單 17.3 stdout_put.rb** ~~~ $stdout.puts "foo", "bar", "baz" ~~~ > **執行示例** ~~~ > ruby stdout_put.rb foo bar baz ~~~ - ***io*.`putc`(*ch*)** 輸出參數 *ch* 指定的字符編碼所對應的字符。參數為字符串時輸出首字符。 **代碼清單 17.4 stdout_putc.rb** ~~~ $stdout.putc(82) # 82 是R 的ASCII 碼 $stdout.putc("Ruby") $stdout.putc("\n") ~~~ > **執行示例** ~~~ > ruby stdout_putc.rb RR ~~~ - ***io*.`print`(*str0, str1,* …)** 輸出參數指定的字符串。參數可指定多個字符串。參數為 `String` 以外的對象時會自動將其轉換為字符串。 - ***io*.`printf`(*fmt, arg0, arg1,* …)** 按照指定的格式輸出字符串。格式 *fmt* 的用法與 `printf` 方法一樣,請參考第 192 頁專欄《printf 方法與 sprintf 方法》。 - ***io*.`write`(*str*)** 輸出參數 *str* 指定的字符串。參數為 `String` 以外的對象時會自動將其轉換為字符串。方法返回值為輸出的字節數。 ~~~ size = $stdout.write("Hello.\n") #=> Hello. p size #=> 6 ~~~ - ***io*<<*str*** 輸出參數 *str* 指定的字符串。`<<` 會返回接收者本身,因此可以像下面這樣寫: ~~~ io << "foo" << "bar" << "baz" ~~~ ### **17.3 文件指針** 一般情況下,我們會以行為單位處理文本數據。由于只有當讀取到換行符時才能知道行的長度,因此,如要讀取第 100 行的數據,就意味著要將這 100 行的數據全部讀取。另外,如果我們修改了數據,行的長度也會隨之變更,這樣一來,文件中后面的數據就都要做出修改。 為了提高讀取效率,可以將文件分成固定長度的文件塊,來直接訪問某個位置的數據(雖然據此可以訪問任意位置的數據,但卻不能處理超過指定長度的數據)。 我們用文件指針(file pointer)或者當前文件偏移量(current file offset)來表示 `IO` 對象指向的文件的位置。每當讀寫文件時,文件指針都會自動移動,而我們也可以使文件指針指向任意位置來讀寫數據。 - ***io*.`pos` *io*.`pos`=(*position*)** 通過 `pos` 方法可以獲得文件指針現在的位置。改變文件指針的位置用 `pos=` 方法。 ~~~ # hello.txt 中的內容為"Hello, Ruby.\n"   File.open("hello.txt") do |io| p io.read(5) #=> "Hello" p io.pos #=> 5 io.pos = 0 p io.gets #=> "Hello, Ruby.\n" end ~~~ - ***io*.`seek`(*offset, whence*)** 移動文件指針的方法。參數 *offset* 為用于指定位置的整數,參數 *whence* 用于指定 *offset* 如何移動(表 17.2)。 **表 17.2 whence 中指定的值** | whence | 意義 | |-----|-----| | `IO::SEEK_SET` | 將文件指針移動到 *offset* 指定的位置 | | `IO::SEEK_CUR` | 將 *offset* 視為相對于當前位置的偏移位置來移動文件指針 | | `IO::SEEK_END` | 將 *offset* 指定為相對于文件末尾的偏移位置 | - ***io*.`rewind`** 將文件指針返回到文件的開頭。`lineno` 方法返回的行編號為 0。 ~~~ # hello.txt 中的內容為"Hello, Ruby.\n" File.open("hello.txt")do |io| p io.gets #=> "Hello,Ruby.\n" io.rewind p io.gets #=> "Hello, Ruby.\n" end ~~~ - ***io*.`truncate`(*size*)** 按照參數 *size* 指定的大小截斷文件。 ~~~ io.truncate(0) # 將文件大小置為0 io.truncate(io.pos) # 刪除當前文件指針以后的數據 ~~~ ### **17.4 二進制模式與文本模式** 正如我們在第 14 章的專欄《關于換行符》中介紹的那樣,不同平臺下的換行符也不同。 雖然各個平臺的換行符不一樣,但為了保證程序的兼容性,會將字符串中的 `"\n"` 轉換為當前 OS 的換行符并輸出。此外,在讀取的時候也會將實際的換行符轉換為 `"\n"`。 圖 17.1 為在 Windows 中轉換換行符的情形。 ![{%}](https://box.kancloud.cn/2015-10-26_562e0200a247d.png) **圖 17.1 Windows 環境中字符 `"\n"` 的轉換** 當需要確定文件大小進行輸入 / 輸出處理時,或者直接使用從其他平臺拷貝的文件時,如果進行換行符轉換,就有可能會引發問題。 為了解決上述那樣的問題,Ruby 中還提供了不進行換行符轉換的方法。換行符處理的前提是以行為單位做輸入 / 輸出處理,需要轉換時稱為文本模式,反之不需要轉換時則稱為二進制模式。 - ***io*.`binmode`** 新的 `IO` 對象默認是文本模式,使用 `binmode` 方法可將其變更為二進制模式。 ~~~ File.open("foo.txt", "w") do |io| io.binmode io.write "Hello, world.\n" end ~~~ 這樣就可以既不用轉換換行符,又能得到與文件中一模一樣的數據。 > **備注** 轉換為二進制模式的 `IO` 對象無法再次轉換為文本模式。 ### **17.5 緩沖** 即使對 `IO` 對象輸出數據,結果也并不一定馬上就會反映在控制臺或者文件中。在使用 `write`、`print` 等方法操作 `IO` 對象時,程序內部會開辟出一定的空間來保存臨時生成的數據副本(圖 17.2)。這部分空間就稱為緩沖(buffer)。緩沖里累積一定量的數據后,就會做實際的輸出處理,然后清空緩沖。 ![{%}](https://box.kancloud.cn/2015-10-26_562e0200b434c.png) **圖 17.2 緩沖的狀態** 像這樣,使用臨時緩沖進行數據處理稱為緩沖處理(buffering)。 在向控制臺輸出的兩種方式(標準輸出與標準錯誤輸出)中,標準錯誤輸出完全不采用緩沖處理。因此,當兩種方式混合使用時,程序實際輸出的順序可能會與程序代碼中記錄的順序不一樣。 我們來看看代碼清單 17.5 的例子(不同平臺下的運行結果可能會不一樣)。 **代碼清單 17.5 test_buffering1.rb** ~~~ $stdout.print "out1 " $stderr.print "err1 " $stdout.print "out2 " $stdout.print "out3 " $stderr.print "err2\n" $stdout.print "out4\n" ~~~ > **執行示例** ~~~ > ruby test_buffering1.rb err1 err2 out1 out2 out3 out4 ~~~ 標準錯誤輸出的主要目的是輸出如警告、錯誤等信息,因此執行結果必須馬上反映出來。再次強調,建議在顯示程序中正常信息以外的信息時使用標準錯誤輸出。 雖然緩沖處理可以提高輸出效率,但有時候我們會希望執行結果可以馬上反映出來,這時我們就可以用下面的方法來同步數據的操作與輸出。 - ***io*.`flush`** 強制輸出緩沖中的數據。在代碼清單 17.5 的基礎上追加 `$stdout.flush` 的調用(代碼清單 17.6)。 **代碼清單 17.6 test_buffering2.rb** ~~~ $stdout.print "out1 "; $stdout.flush $stderr.print "err1 " $stdout.print "out2 "; $stdout.flush $stdout.print "out3 "; $stdout.flush $stderr.print "err2\n" $stdout.print "out4\n" ~~~ > **執行示例** ~~~ > ruby test_buffering2.rb out1 err1 out2 out3 err2 out4 ~~~ - ***io*.`sync` *io*.`sync`=(*state*)** 通過 `io.sync = true`,程序寫入緩沖時 `flush` 方法就會被自動調用。 **代碼清單 17.7 test_buffering3.rb** ~~~ $stdout.sync = true # 同步輸出處理 $stdout.print "out1 " $stderr.print "err1 " $stdout.print "out2 " $stdout.print "out3 " $stderr.print "err2\n" $stdout.print "out4\n" ~~~ 即使不逐次調用 flush 方法,也可以像下面那樣按順序輸出: > **執行示例** ~~~ > ruby test_buffering3.rb out1 err1 out2 out3 err2 out4 ~~~ ### **17.6 與命令進行交互** 雖然 Ruby 是幾乎什么都能實現的強大的語言,但是也會有與其他命令進行數據交換的時候。例如,讀取使用 GUN zip 壓縮的數據的時候,使用 gunzip 命令會很方便。在 Ruby 中,使用 `IO.popen` 方法可以與其他命令進行數據處理。 - **IO.`popen`(*command, mode*)** 參數 *mode* 的使用方法與 `File.open` 方法是一樣的,參數缺省時默認為 `"r"` 模式。 用 `IO.popen` 方法生成的 `IO` 對象的輸入 / 輸出,會關聯啟動后的命令 *command* 的標準輸入 / 輸出。也就是說,`IO` 對象的輸出會作為命令的輸入,命令的輸出則會作為 `IO` 對象的輸入。 我們來改造一下第 3 章的 simple_grep.rb,利用 gunzip 命令解壓處理擴展名為 .gz 的文件(-c 為將解壓后的結果寫入到標準輸出時的選項)。 **代碼清單 17.8 simple_grep_gz.rb** ~~~ pattern = Regexp.new(ARGV[0]) filename = ARGV[1] if /.gz$/ =~ filename file = IO.popen("gunzip -c #{filename}") else file = File.open(filename) end file.each_line do |text| if pattern =~ text print text end end ~~~ > **注** 執行代碼清單 17.8 時需要 gunzip 命令。 - **`open`("*|command*"*, mode*)** 將帶有管道符號的命令傳給 `open` 方法的效果與使用 `IO.popen` 方法是一樣的。 ~~~ filename = ARGV[0] open("|gunzip -c #{filename}") do |io| io.each_line do |line| print line end end ~~~ ### **17.7 open-uri 庫** 除了控制臺、文件以外,進程間通信時使用的管道(pipe)、網絡間通信時使用的套接字(socket)也都可以作為 `IO` 對象使用。管道、套接字的使用方法超出了本書的范圍,因此不做詳細說明,這里我們簡單地介紹一下利用 HTTP、FTP 從網絡獲取數據的方法。 通過 `require` 引用 `open-uri` 庫后,我們就可以像打開普通的文件一樣打開 HTTP、FTP 的 URL(代碼清單 17.9)。使用 `open-uri` 庫的功能時,不要使用 `File.open` 方法,只使用 `open` 方法即可。 **代碼清單 17.9 read_uri.rb** ~~~ require "open-uri" # 通過HTTP 讀取數據 open("http://www.ruby-lang.org") do |io| puts io.read # 將Ruby 的官方網頁輸出到控制臺 end # 通過FTP 讀取數據 url = "ftp://www.ruby-lang.org/pub/ruby/2.0/ruby-2.0.0-p0.tar.gz" open(url) do |io| open("ruby-2.0.0-p0.tar.gz", "w") do |f| # 打開本地文件 f.write(io.read) end end ~~~ 通過 HTTP 協議時,服務器會根據客戶端的狀態改變應答的內容,比如返回中文或英語的網頁等。為了實現這個功能,請求時就需要向服務器發送元信息(meta information)。例如,代碼清單 17.10 中的 HTTP 頭部信息 Accept-Language 就表示優先接收中文網頁。指定 HTTP 頭部信息時,會將其以散列的形式傳遞給 `open` 方法的第 2 個參數。 **代碼清單 17.10 read_uri_cn.rb** ~~~ require "open-uri" options = { "Accept-Language" => "zh-cn, en;q=0.5", } open("http://www.ruby-lang.org", options){|io| puts io.read } ~~~ ### **17.8 stringio 庫** 在測試程序時,雖然我們會希望知道向文件或控制臺輸出了什么,但程序實際執行的結果卻往往很難知道。為此,我們可以通過向模擬 `IO` 對象的對象進行輸出來確認執行結果。 `StringIO` 就是用于模擬 `IO` 對象的對象。通過 `require` 引用 `stringio` 庫后,就可以使用 `StringIO` 對象了(代碼清單 17.11)。 **代碼清單 17.11 stringio_puts.rb** ~~~ require "stringio" io = StringIO.new io.puts("A") io.puts("B") io.puts("C") io.rewind p io.read #=> "A\nB\nC\n" ~~~ 實際上,向 `StringIO` 對象進行的輸出并不會被輸出到任何地方,而是會被保存在對象中,之后就可以使用 `read` 方法等來讀取該輸出。 `StringIO` 對象還有另外一種用法,那就是將字符串數據當作 `IO` 數據處理。將大數據保存在文件中,并將小數據直接傳輸給別的處理時,通過使用 `StringIO` 對象,程序就可以不區分對待 `IO` 對象和字符串了。實際上,之前介紹的用 `open-uri` 庫打開 URI 時,也是有時候返回 `IO` 對象,有時候返回 `StringIO` 對象。不過一般情況下,我們不需要在意這兩者的區別。通過將數據字符串傳遞給 `StringIO.new` 方法的參數,就可以由字符串創建 `StringIO` 對象(代碼清單 17.12)。 **代碼清單 17.12 stringio_gets.rb** ~~~ require "stringio" io = StringIO.new("A\nB\nC\n") p io.gets #=> "A\n" p io.gets #=> "B\n" p io.gets #=> "C\n" ~~~ `StringIO` 對象可以模擬本章中介紹的大部分輸入 / 輸出操作。 ### **練習題** 1. 創建腳本,讀取文本文件中的內容,按以下條件進行處理。這里將空白和換行以外的連續字符串稱為“單詞”。 (a)統計文本的行數 (b)統計文本的單詞數 (c)統計文本的字符數 2. 創建腳本,按照以下條件覆蓋文本文件中原有的數據。 (a)將文件中的行逆序排列 (b)保留文件中第 1 行數據,其余全部刪除 (c)保留文件中最后 1 行數據,其余全部刪除 3. 定義一個功能類似于 Unix 中的 tail 命令的 `tail` 方法。 `tail` 方法有兩個參數。 **`tail`( 行數, 文件名)** 從文件的末尾開始數,輸出參數指定的行數的內容。也就是說,假設有一個有 100 行數據的文件 some_file.txt,執行 `tail(10, "some_file.txt")` 后,程序就會跳過前 90 行數據,只在標準輸出中輸出最后 10 行數據。 > 參考答案:請到圖靈社區本書的“隨書下載”處下載([http://www.ituring.com.cn/book/1237](http://www.ituring.com.cn/book/1237))。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看