Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何删除带有露比的文本文件中间的数据行_Ruby On Rails_Ruby_File_Csv_File Io - Fatal编程技术网

Ruby on rails 如何删除带有露比的文本文件中间的数据行

Ruby on rails 如何删除带有露比的文本文件中间的数据行,ruby-on-rails,ruby,file,csv,file-io,Ruby On Rails,Ruby,File,Csv,File Io,我知道如何写入文件和读取文件,但除了将整个文件读入内存、对其进行操作并重写整个文件之外,我不知道如何修改文件。对于大文件,这不是很有效率 我真的不知道追加和写入之间的区别 例如 如果我有一个包含以下内容的文件: Person1,will,23 Person2,Richard,32 Person3,Mike,44 如何删除包含Person2的行?阅读: 您可以通过多种方式删除行: 模拟删除。也就是说,只需用空格覆盖行的内容。稍后,当您读取和处理文件时,只需忽略这些空行即可 优点:这既简单又快速

我知道如何写入文件和读取文件,但除了将整个文件读入内存、对其进行操作并重写整个文件之外,我不知道如何修改文件。对于大文件,这不是很有效率

我真的不知道追加和写入之间的区别

例如

如果我有一个包含以下内容的文件:

Person1,will,23
Person2,Richard,32
Person3,Mike,44
如何删除包含Person2的行?

阅读:


您可以通过多种方式删除行:

  • 模拟删除。也就是说,只需用空格覆盖行的内容。稍后,当您读取和处理文件时,只需忽略这些空行即可

    优点:这既简单又快速缺点:这不是真正的数据删除(文件不会收缩),在读取/处理文件时需要做更多的工作

    代码:

  • 做真正的删除。这意味着这条线将不再存在。因此,您必须阅读下一行并用它覆盖当前行。然后对以下所有行重复此操作,直到到达文件末尾。这似乎是一个容易出错的任务(不同长度的行等),因此这里有一个无错误的替代方案:打开临时文件,将行写入(但不包括)要删除的行,跳过要删除的行,将其余的行写入临时文件。删除原始文件并重命名临时文件以使用其名称。完成了

    虽然从技术上讲,这是对文件的完全重写,但它与您要求的有所不同。该文件不需要完全加载到内存中。一次只需要一行。Ruby为此提供了一个方法:

    优点:无假设。行被删除。读取代码不需要修改Cons:删除行时需要做更多的工作(不仅是代码,还有IO/CPU时间)

    在@azgult的文章中有一个片段说明了这种方法


您可以打开文件,逐行读取,并在新文件中添加要保留的行。这使您能够最大程度地控制保留哪些行,而不会破坏原始文件

File.open('output_file_path', 'w') do |output| # 'w' for a new file, 'a' append to existing
  File.open('input_file_path', 'r') do |input|
    line = input.readline
    if keep_line(line) # logic here to determine if the line should be kept
      output.write(line)
    end
  end
end
如果知道要删除的块的开头和结尾的位置,可以打开文件,从头开始读取,然后查找到结尾并继续读取

查找read方法的参数,并在此处阅读有关查找的内容:


由于文件基本上是以连续数据块的形式保存到磁盘上的,因此删除其中的任何部分都需要至少重写之后的内容。这在本质上意味着——正如您所说的——它对于大型文件不是特别有效。因此,限制文件大小通常是一个好主意,这样就不会出现此类问题

一些“折衷”解决方案可能是将文件逐行复制到第二个文件,然后移动该文件以替换第一个文件。这样可以避免将文件加载到内存中,但不会避免任何硬盘访问:

require 'fileutils'

open('file.txt', 'r') do |f|
  open('file.txt.tmp', 'w') do |f2|
    f.each_line do |line|
       f2.write(line) unless line.start_with? "Person2"
    end
  end
end
FileUtils.mv 'file.txt.tmp', 'file.txt'

更有效的方法是读写打开文件,跳转到您想要删除的位置,然后将其余数据移回原来的位置——但这会产生一些非常难看的代码(现在不能要求我这么做)。

Sawa,你总是在帮我。因此,每次程序保存一个文件时,它都会覆盖整个文件?您计划如何在不读取文件的情况下找到要删除的行?“它总是一个特定的行号吗?”Senjai Sergio提出了一些可能有用的建议,如果这是正确的,那么我之前的评论是错误的。很抱歉。是否要删除Person2或包含Person2的行?对于包含Person2的行,我将使用正则表达式查找该行。不保证每次都在同一行。这会覆盖整个文件。我认为OP知道如何做到这一点,而这并不是问题所在。根据其他答案,这似乎是唯一的方法。是否可以只覆盖文件的一部分(带空格),而不覆盖整个文件?当然,这是可能的。在写模式下打开一个文件,寻找所需的偏移量并开始写。不是写模式,而是读/写模式(“r+”标志)需要覆盖部分。在回答中扩展该模式(显示实际代码)可能会有所帮助。@juanpastas:没有区别,这些是别名。
File.open('output_file_path', 'w') do |output| # 'w' for a new file, 'a' append to existing
  File.open('input_file_path', 'r') do |input|
    line = input.readline
    if keep_line(line) # logic here to determine if the line should be kept
      output.write(line)
    end
  end
end
require 'fileutils'

open('file.txt', 'r') do |f|
  open('file.txt.tmp', 'w') do |f2|
    f.each_line do |line|
       f2.write(line) unless line.start_with? "Person2"
    end
  end
end
FileUtils.mv 'file.txt.tmp', 'file.txt'