1. 程式人生 > >ruby檔案讀寫的好文章 ruby way之IO之一

ruby檔案讀寫的好文章 ruby way之IO之一

 

http://simohayha.javaeye.com/blog/153398

1 開啟和關閉一個檔案
類方法File.new 開啟一個檔案,並將它例項化為一個File物件,他的第一個引數是檔名.
可選的第二個引數叫做 mode string(這個也是從c得來的).他的意思是怎樣開啟一個檔案(讀,寫或者其他的).預設是'r'(也就是讀).
Ruby程式碼
  1. file1 = File.new("one")       # Open for reading
  2. file2 = File.new("two","w")  # Open for writing
file1 = File.new("one")       # Open for reading  file2 = File.new("two", "w")  # Open for writing
另外一種new的形式是三個引數的,其中第二個引數是指定了這個檔案的原始的許可權(經常表示為一個八進位制的數).第三個引數是一系列Ored標誌 的組合.標誌是個常量比如File:CREAT(如果檔案不存在則建立它)和File:RDONLY(以只讀方式開啟檔案)。不過這種形式很少使用:

Ruby程式碼
  1. file = File.new("three", 0755,File::CREAT|File::WRONLY)  
file = File.new("three", 0755, File::CREAT|File::WRONLY)


出於對作業系統和執行環境的考慮,如果你打開了一個檔案的話,你就必須關閉它。當你開啟一個檔案用於寫時,你更應該這樣做,從而才能免於丟失資料.close方法就是關閉一個檔案:

Ruby程式碼
  1. out =
    File.new("captains.log","w")  
  2. # Process as needed...
  3. out.close  
out = File.new("captains.log", "w") # Process as needed... out.close

這裡還有一個open方法,它的最簡單的形式是和new同義的:
Ruby程式碼
  1. trans = File.open("transactions","w")  
trans = File.open("transactions","w")


但是open方法還能夠帶一個block作為引數,當存在block時,開啟的檔案將會做為一個引數傳遞給block.這時這個檔案將會在這個block的作用域裡,保持開啟,直到block結束時,自動關閉:

Ruby程式碼
  1. File
    .open("somefile","w")do |file|  
  2.    file.puts "Line 1"
  3.    file.puts "Line 2"
  4.    file.puts "Third and final line"
  5. end
File.open("somefile","w") do |file|   file.puts "Line 1"   file.puts "Line 2"   file.puts "Third and final line" end


2 更新檔案

假設我們想要開啟一個檔案用於讀和寫,簡單的加一個'+'號到file mode就行了:
Ruby程式碼
  1. f1 = File.new("file1","r+")  
  2. # Read/write, starting at beginning of file.
  3. f2 = File.new("file2","w+")  
  4. # Read/write; truncate existing file or create a new one.
  5. f3 = File.new("file3","a+")  
  6. # Read/write; start at end of existing file or create a
  7. # new one.
f1 = File.new("file1", "r+") # Read/write, starting at beginning of file. f2 = File.new("file2", "w+") # Read/write; truncate existing file or create a new one. f3 = File.new("file3", "a+") # Read/write; start at end of existing file or create a # new one.


3 追加一個檔案

假設我們想要追加一段資訊到一個存在檔案,當我們開啟檔案時使用'a'作為file mode就行了:

Ruby程式碼
  1. logfile = File.open("captains_log","a")  
  2. # Add a line at the end, then close.
  3. logfile.puts "Stardate 47824.1: Our show has been canceled."
  4. logfile.close  
logfile = File.open("captains_log", "a") # Add a line at the end, then close. logfile.puts "Stardate 47824.1: Our show has been canceled." logfile.close


4隨機存取一個檔案

如果你想隨即存取一個檔案,你能夠使用seek方法,它是File從Io繼承而來的.它的最簡單的使用就是指定一個位元組位置.這個位置是相對於檔案開始的位置(開始的位置是0):
Ruby程式碼
  1. # myfile contains only: abcdefghi
  2. file = File.new("myfile")  
  3. file.seek(5)  
  4. str = file.gets                   # "fghi"
# myfile contains only: abcdefghi file = File.new("myfile") file.seek(5) str = file.gets                   # "fghi"


如果你能確定每一行都是固定的長度,你就能seek指定的行:
Ruby程式碼
  1. # Assume 20 bytes per line.
  2. # Line N starts at byte (N-1)*20
  3. file = File.new("fixedlines")  
  4. file.seek(5*20)                   # Sixth line!
  5. # Elegance is left as an exercise.
# Assume 20 bytes per line. # Line N starts at byte (N-1)*20 file = File.new("fixedlines") file.seek(5*20)                   # Sixth line! # Elegance is left as an exercise.
如果你想做一個相對的搜尋,你就要使用第二個引數,常量 IO::SEEK_CUR表示當前的位置,而第一個引數則就是相對於當前位置的偏移量(可能是負數):

Ruby程式碼
  1. file = File.new("somefile")  
  2. file.seek(55)                 # Position is 55
  3. file.seek(-22, IO::SEEK_CUR)  # Position is 33
  4. file.seek(47, IO::SEEK_CUR)   # Position is 80
file = File.new("somefile") file.seek(55)                 # Position is 55 file.seek(-22, IO::SEEK_CUR)  # Position is 33 file.seek(47, IO::SEEK_CUR)   # Position is 80


你也能從檔案的結束位置開始搜尋:

Ruby程式碼
  1. file.seek(-20, IO::SEEK_END)  # twenty bytes from eof
file.seek(-20, IO::SEEK_END)  # twenty bytes from eof
方法tell得到檔案的當前位置,pos是它的別名:

Ruby程式碼
  1. file.seek(20)  
  2. pos1 = file.tell             # 20
  3. file.seek(50, IO::SEEK_CUR)  
  4. pos2 = file.pos              # 70
file.seek(20) pos1 = file.tell             # 20 file.seek(50, IO::SEEK_CUR) pos2 = file.pos              # 70
rewind方法將會將檔案指標的位置設回到開始的位置,也就是0.

5 操作二進位制檔案

在很久以前,c語言通過在file mode後附加一個'b'來表示將檔案用二進位制模式開啟.在今天,二進位制檔案的處理已經沒有那麼麻煩了。在ruby中,一個字串很容易儲存一個二進位制資料,而且也不用通過任何特殊的方式來讀檔案.

可是在windows下是例外,在他下面,二進位制檔案和文字檔案的不同是,在二進位制mode下,結束行不能被轉義為一個單獨的換行,而是被儲存為一個回車換行對.
另外的不同是,在文字模式下 control-Z被作為檔案的結束:

Ruby程式碼
  1. # Create a file (in binary mode)
  2. File.open("myfile","wb") {|f| f.syswrite("12345\0326789\r") }  
  3. # Above note the embedded octal 032 (^Z)
  4. # Read it as binary
  5. str = nil
  6. File.open("myfile","rb") {|f| str = f.sysread(15) }  
  7. puts str.size           # 11
  8. # Read it as text
  9. str = nil
  10. File.open("myfile","r") {|f| str = f.sysread(15) }  
  11. puts str.size           # 5
# Create a file (in binary mode) File.open("myfile","wb") {|f| f.syswrite("12345\0326789\r") } # Above note the embedded octal 032 (^Z) # Read it as binary str = nil  File.open("myfile","rb") {|f| str = f.sysread(15) } puts str.size           # 11 # Read it as text str = nil File.open("myfile","r") {|f| str = f.sysread(15) } puts str.size           # 5
這邊注意,這些程式碼都是在windows下才會打印出後面的結果,如果是在linux兩處都會打印出11.
再看下面的程式碼:
Ruby程式碼
  1. # Input file contains a single line: Line 1.
  2. file = File.open("data")  
  3. line = file.readline             # "Line 1.\n"
  4. puts "#{line.size} characters."   # 8 characters  
  5. file.close  
  6. file = File.open("data","rb")  
  7. line = file.readline             # "Line 1.\r\n"
  8. puts "#{line.size} characters."   # 9 characters 二進位制模式的結尾是一個回車換行對.  
  9. file.close  
# Input file contains a single line: Line 1. file = File.open("data") line = file.readline             # "Line 1.\n" puts "#{line.size} characters."  # 8 characters file.close file = File.open("data","rb") line = file.readline             # "Line 1.\r\n" puts "#{line.size} characters."  # 9 characters 二進位制模式的結尾是一個回車換行對. file.close
binmode方法能夠轉換當前的流為二進位制模式,這邊要注意的是,一旦切換過去,就不能切換回來了:
Ruby程式碼
  1. file = File.open("data")  
  2. file.binmode  
  3. line = file.readline             # "Line 1.\r\n"
  4. puts "#{line.size} characters."   # 9 characters  
  5. file.close  
file = File.open("data") file.binmode line = file.readline             # "Line 1.\r\n" puts "#{line.size} characters."  # 9 characters file.close
如果你想使用更底層的輸入輸出,那你可以選擇sysread和syswrite方法,他們接受一定數量的位元組作為引數 .
Ruby程式碼
  1. input = File.new("myfile",'a+')  
  2. output = File.new("outfile",'a+')  
  3. instr = input.sysread(10);  
  4. puts instr  
  5. bytes = output.syswrite("This is a test.")  
input = File.new("myfile",'a+') output = File.new("outfile",'a+') instr = input.sysread(10); puts instr bytes = output.syswrite("This is a test.")

如果檔案指標已經到達檔案的結尾時,sysread方法將會丟擲一個異常.

這邊要注意 Array 的pack和string的unpack方法,對於處理二進位制資料非常有用.

=======================================================

讀檔案:
第一種方法:
$result='d:\\rs.txt'
File.open($result, "r") do |file|  
file.each_line do |line|
     if line.length>20
     puts line.chop.length    #去掉最後一個換行字元,並顯示該行實際字串的長度
      puts line
    end
  end
  end
第二種方法:
filename='d:\\rs.txt'
while File.exists?(filename) #如果原始檔存在就執行下面的操作
file=File.open(filename,'r')
  while (lines=file.gets)
puts lines
end


寫檔案:
$filename="C:\\Automation\\rss"+".txt"
$logfile = File.new($filename,"a")
iCount=0

while(iCount<10)      //迴圈寫入10行
$logfile.puts "http://xxxx/rs#{iCount}.xml"
iCount=iCount+1
end

今天又笨了一次,由於要比較兩個檔案的不同,於是考慮用ruby來寫個指令碼

實現,剛開始的時候使用雙重
File.open($file1, "r") do |file1|  
file1.each_line do |line1|
總是報錯,

後來改成先把檔案讀到一個數組裡,然後迴圈比較,成功.

其實這是個笨方法,在unix下使用三個命令就可以完成了.

1.先使用sort指令將檔案中的資料按照要求的索引進行排序,
2.然後使用uniq指令將重複資料去掉
3.再使用diff命令就可以了.

========================================

ruby讀寫文字檔案的簡單例子,除了演示文字檔案的讀寫外,這段ruby程式可以從文字檔案中刪除包含某些字串的行。
用法:ruby delline.rb 檔名 字串1 字串2 字串n
將刪除同時包含字串1 字串2 字串n的行。
ruby的開發環境這裡下載
http://www.ruby-lang.org/en/downloads/
直接下載最近的穩定版Windows安裝包
http://rubyforge.org/frs/download.php/29263/ruby186-26.exe

程式碼如下

  1. ifARGV.length<2then
  2. puts"USAGE: ruby delline.rb text_file_name str1 [str2 ...]"
  3. exit
  4. end
  5. i_file_name = ARGV[0]
  6. i_file_name_bak = i_file_name +".bak"
  7. ifFileTest.exist?(i_file_name)then
  8. File.rename(i_file_name,i_file_name_bak)
  9. else
  10. puts"File #{i_file_name} was not found"
  11. exit
  12. end
  13. i_file = File.new(i_file_name_bak,"r")
  14. o_file = File.new(i_file_name,"w")
  15. i_file.each_linedo |line|
  16. delete_flag =true
  17. 1.upto(ARGV.length - 1)do |x|
  18. if !line.include?(ARGV[x])then
  19. delete_flag =false
  20. break
  21. end
  22. end
  23. o_file.putslineif !delete_flag
  24. end
  25. i_file.close
  26. o_file.close

 File.open("cmd.txt","r") do |file|
while line=file.gets
puts line
end

end

puts

file=File.new("cmd.txt","r")
file.each_line do |line|
puts line

end



IO.foreach("cmd.txt") do |line|  
   puts line if line =~ /target/  
   puts line if line !~ /target/
end
  
# Another way...  
file = File.new("cmd.txt")  
file.each do |line|  
   puts line if line =~ /target/  

end



arr = IO.read("cmd.txt")  

bytes = arr.size
puts "myfile has #{bytes} bytes in it."



arr = IO.readlines("cmd.txt")
puts arr
lines = arr.size  
puts "myfile has #{lines} lines in it."



file2=File.new("cmd.txt");

puts File.expand_path("cmd.txt")

file = File.new("cmd.txt")  
e_count = 0  
file.each_byte do |byte|  
e_count += 1 if byte == ?e

end

puts File.exist?("testR.txt")
file1=File.new("testR.txt","w") #沒有檔案則會自動建立
puts File.exist?("testR.txt")
puts file1.write("ttt333\nttt444\n")


字串當檔案用.rb
require 'stringio'
  
ios = StringIO.new("abcdefghijkl\nABC\n123")  
  
ios.seek(5)  
ios.puts("xyz")  

puts ios.tell             # 8  

puts ios.string.dump      # "abcdexyzijkl\nABC\n123"  
  
c = ios.getc  
puts "c = #{c}"           # c = 105  

ios.ungetc(?w)  

puts ios.string.dump      # "abcdexyzwjkl\nABC\n123"  

puts "Ptr = #{ios.tell}"

s1 = ios.gets             # "wjkl"  
s2 = ios.gets             # "ABC"