2011-12-24 19 views
12

Tôi muốn thêm một dòng duy nhất để đầu một tập tin với Ruby như thế này:Thêm vào trước một dòng duy nhất để nộp với Ruby

# initial file contents 
something 
else 

# file contents after prepending "hello" on its own line 
hello 
something 
else 

Các mã sau chỉ thay thế các nội dung của toàn bộ tập tin:

f = File.new('myfile', 'w') 
f.write "test string" 

Trả lời

19

Đây là một nhiệm vụ khá phổ biến:

original_file = './original_file' 
new_file = original_file + '.new' 

Thiết lập kiểm tra:

File.open(original_file, 'w') do |fo| 
    %w[something else].each { |w| fo.puts w } 
end 

Đây là mã thực tế:

File.open(new_file, 'w') do |fo| 
    fo.puts 'hello' 
    File.foreach(original_file) do |li| 
    fo.puts li 
    end 
end 

Đổi tên tập tin cũ để an toàn điều gì đó:

File.rename(original_file, original_file + '.old') 
File.rename(new_file, original_file) 

Chứng minh rằng nó hoạt động:

puts `cat #{original_file}` 
puts '---' 
puts `cat #{original_file}.old` 

Những kết quả đầu ra:

hello 
something 
else 
--- 
something 
else 

Bạn không muốn tải tệp hoàn toàn vào bộ nhớ. Điều đó sẽ hoạt động cho đến khi bạn nhận được một tệp lớn hơn phân bổ RAM của bạn và máy sẽ bị thu thập dữ liệu hoặc tệ hơn, bị treo.

Thay vào đó, hãy đọc từng dòng một. Đọc các dòng riêng lẻ vẫn cực kỳ nhanh và có thể mở rộng được. Bạn sẽ phải có đủ chỗ trên ổ đĩa để lưu trữ tệp gốc và tệp tạm thời.

2

Không có cơ chế nào để thực hiện những gì bạn muốn làm dễ dàng. Thay vào đó, bạn sẽ cần mở tệp, xóa tệp, mở tệp mới theo tên cũ để viết, viết nội dung của bạn và sau đó ghi tệp mới từ nội dung của tệp cũ. Đó là khá phức tạp nghe nhưng là đơn giản trong mã:

$ cat prepend.rb 
#!/usr/bin/ruby 

File.open("passwd", "r") do |orig| 
    File.unlink("passwd") 
    File.open("passwd", "w") do |new| 
     new.write "test string" 
     new.write(orig.read()) 
    end 
end 

Lưu ý rằng cơ chế Tôi đã sử dụng không bận tâm kiểm tra lỗi - có lẽ bạn nên xử lý các lỗi trên mỗi File.open() yêu cầu và File.unlink() yêu cầu - và nó giả định rằng toàn bộ nội dung của tệp sẽ phù hợp với bộ nhớ. Một ví dụ nhỏ:

$ rm passwd 
$ cp /etc/passwd . 
$ ./prepend.rb 
$ head passwd 
test stringroot:x:0:0:root:/root:/bin/bash 
daemon:x:1:1:daemon:/usr/sbin:/bin/sh 
bin:x:2:2:bin:/bin:/bin/sh 
sys:x:3:3:sys:/dev:/bin/sh 
sync:x:4:65534:sync:/bin:/bin/sync 
games:x:5:60:games:/usr/games:/bin/sh 
man:x:6:12:man:/var/cache/man:/bin/sh 
lp:x:7:7:lp:/var/spool/lpd:/bin/sh 
mail:x:8:8:mail:/var/mail:/bin/sh 
news:x:9:9:news:/var/spool/news:/bin/sh 
$ 

Nếu bạn muốn xử lý các file mà có thể không phù hợp hoàn toàn trong bộ nhớ, bạn nên mã hóa một vòng loại như thế này (chưa được kiểm tra - tốt hơn xem xét nó pseudo-code):

while (data=orig.read(4096)) { 
    new.write(data) 
} 

Thay vào đó, bạn có thể ghi vào tệp tạm thời và nếu quá trình ghi thành công, hãy sau đó xóa tệp và đổi tên tệp tạm thời. Cách tiếp cận nào có ý nghĩa nhất đối với bạn.

7

fwiw này dường như làm việc:

#!usr/bin/ruby 

f = File.open("myfile", "r+") 
lines = f.readlines 
f.close 

lines = ["something\n"] + lines 

output = File.new("myfile", "w") 
lines.each { |line| output.write line } 
output.close 
+5

Hãy cẩn thận khi vuốt tệp. Nó không phải là giải pháp có thể mở rộng để đọc toàn bộ tệp vào bộ nhớ. –

+0

Tôi thích điều này để nhắn tin đơn giản, cá nhân. – steve

+0

Giải pháp tốt nhất cho trường hợp đơn giản. –

2

Bạn có thể thử này:

File.copy_stream(myfile,tempfile) 
f = File.open(myfile,'w') 
f.write("Hello\n#{File.open(tempfile,'r').read}") 
f.close 
File.delete(tempfile) 
2

tôi đã nảy ra một cái gì đó như thế này, nó là mô tả nhiều hơn một chút và ít khó hiểu hơn các giải pháp khác mà tôi đã nhìn thấy:

def file_prepend(file, str) 
    new_contents = "" 
    File.open(file, 'r') do |fd| 
    contents = fd.read 
    new_contents = str << contents 
    end 
    # Overwrite file but now with prepended string on it 
    File.open(file, 'w') do |fd| 
    fd.write(new_contents) 
    end 
end 

Và bạn có thể sử dụng nó như thế này:

file_prepend("target_file.txt", "hello world!\n") 
+0

Câu trả lời hay! Có thể tái sử dụng nó trong suốt một ứng dụng. Giải pháp IMO tốt nhất. Cảm ơn! – sjsc

2

Như một số người đã nói, có lẽ không sử dụng điều này cho các tệp lớn hơn, nhưng đó là một khởi đầu đơn giản.

rd = IO.read 'myfile' 
IO.write 'myfile', "hello\n" + rd 
0

Từ dòng lệnh, bạn có thể làm:

ruby -i -pe '$_= "prepended text\n"+$_ if $. == 1' myfile 

hoặc hiệu quả hơn

ruby -i -pe 'BEGIN { gets; print "prepended text\n" + $_ }; ' myfile 

Đáng buồn thay, nó quay ra, các tùy chọn -i (tại chỗ) không phải là thực sự tại chỗ, mặc dù (và cũng không phải là tùy chọn tại chỗ sed s cho vấn đề đó) - tệp của tôi sẽ có một inode khác nhau sau khi op.

Điều đó làm tôi buồn, vì hiệu quả, tôi không thể lọc qua (thêm vào) một tệp lớn nếu tôi không có đủ dung lượng đĩa cho hai bản sao của nó.

Nó không thực sự khó khăn để làm điều đó tại chỗ, mặc dù (lọc nói chung, không chỉ cho dòng đầu tiên). Tất cả những gì bạn cần làm là:

1) đảm bảo bạn có các con trỏ đọc và ghi riêng biệt (hoặc các đối tượng Tệp riêng biệt để đọc và viết) 2) đảm bảo bạn đã đệm các phần chưa đọc mà bạn sẽ viết lại 3) cắt ngắn để tập tin ở cuối nếu hoạt động lọc của bạn nên kết thúc với một tập tin ngắn hơn

Tôi đã viết lớp bao bọc cho rằng tại https://github.org/pjump/i_rewriter.

Với nó, bạn có thể làm

Rewriter.new("myfile") do |line, index| 
    index == 0 ? "prepended text\n" + line : line 
end 

hoặc qua các nhân thực thi:

$ i_rewriter 'index == 0 ? "prepended text\n" + line : line' myfile 

Sử dụng một cách cẩn thận (nó có thể bị hỏng tệp của mình nếu bị gián đoạn).

0

Tinh khiết nhưng hoạt động. Giảm thiểu các hoạt động liên quan đến tệp.

`#!/bin/ruby 
inv_file = File.open("./1.txt","r+") { |f| 
    #Read file string by-string 
    until f.eof? 
     #Searching for some 
     if f.readline[/condition here/] 
      #remember position 
      offset = f.pos 
      #Find it? - stop reading 
      break 
     end 
    end 
    #Remember what contains rest of file 
    tail = f.readlines 
    #Again to offset 
    f.pos = offset 
    #insert what necessary 
    f.puts "INSERTED" 
    #reconstruct tail 
    f.write tail.join 
    }` 
Các vấn đề liên quan