Class: CSV
- Inherits:
-
Object
- Object
- CSV
- Defined in:
- lib/clir/CSV_extension.rb
Class Attribute Summary collapse
-
.headers_for_test ⇒ Object
readonly
Pour pouvoir tester l’entête dans les tests.
Class Method Summary collapse
-
.readlines_backward(path, **options, &block) ⇒ Object
(also: readlines_backwards, foreach_backward, foreach_backwards)
Lecture d’un fichier CSV à partir de la fin.
-
.readlines_backward_in_small_file(path, **options, &block) ⇒ Object
Lecture à l’envers dans un petit fichier.
Class Attribute Details
.headers_for_test ⇒ Object (readonly)
Pour pouvoir tester l’entête dans les tests
6 7 8 |
# File 'lib/clir/CSV_extension.rb', line 6 def headers_for_test @headers_for_test end |
Class Method Details
.readlines_backward(path, **options, &block) ⇒ Object Also known as: readlines_backwards, foreach_backward, foreach_backwards
Lecture d’un fichier CSV à partir de la fin
Les arguments sont les mêmes que pour readlines
Pour rappel :
+options+ peut contenir
:headers À true, on tient compte des entêtes et on
retourne des CSV::Row. Sinon, on retourne une
Array simple.
:headers_converters
Convertisseur pour les noms des colonnes.
:downcase ou :symbol
:converters
Liste de convertisseurs pour les données.
Principalement :numeric, :date
:col_sep
Séparateur de colonne. Par défaut une virgule.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/clir/CSV_extension.rb', line 26 def readlines_backward(path, **, &block) ||= {} .key?(:col_sep) || .merge!(col_sep: ',') file = File.new(path) size = File.size(file) if size < ( 1 << 16 ) return readlines_backward_in_small_file(path, **, &block) end # # Si options[:headers] est true, il faut récupérer la première # ligne et la transformer en entête # @note Cet entête permettra d'instancier les rangées (\CSV::Row) # headers = nil if [:headers] begin fileh = File.open(path,'r') header = fileh.gets.chomp ensure fileh.close end table = CSV.parse(header, **) headers = table.headers @headers_for_test = headers # pour les tests end if block_given? # # # Avec un bloc fourni, on va lire ligne par ligne en partant # de la fin. # buffer_size = 10000 # disons que c'est la longueur maximale d'une ligne # # On se positionne de la fin - la longueur du tampo dans le # fichier à lire # file.seek(-buffer_size, IO::SEEK_END) # # Le tampon courant (il contient tout jusqu'à ce qu'il y ait # au moins une ligne) # buffer = "" # # On boucle tant qu'on n'interrompt pas (pour le moment) # while true # # On lit la longueur du tampon en l'ajoutant à ce qu'on a # déjà lu ou ce qui reste. # Celui pourra contenir une ou plusieurs lignes, la première # pourra être tronquée # buffer = file.read(buffer_size) + buffer # # Nombre de lignes # (utile ?) nombre_lignes = buffer.count("\n") # # On traite les lignes du buffer (en gardant ce qui dépasse) # if nombre_lignes > 0 # puts "Position dans le fichier : #{file.pos}".bleu # puts "Nombre de lignes : #{nombre_lignes}".bleu lines = buffer.split("\n").reverse # # On laisse la dernière ligne, certainement incomplète, dans # le tampon. Elle sera ajoutée à la fin de ce qui précède # buffer = lines.pop # # Boucle sur les lignes # # @note : un break, dans le &block, interrompra la boucle # lines.each do |line| line = line.chomp # Je crois que c'est ça qui prend trop de temps # line = "#{header}\n#{line}\n" if options[:headers] # puts "line parsée : #{line.inspect}".bleu # line_csv = CSV.parse(line, **line_csv_options) # puts "line_csv: #{line_csv.inspect}::#{line_csv.class}".orange # yield line_csv[0] # # # Convertir les valeurs si des convertisseurs sont # définis # NOTE : Pour le moment, je reste simple et un peu brut # values = line.split([:col_sep]) if [:converters] values = values.collect do |value| [:converters].each do |converter| if converter == :numeric && value.numeric? value = value.to_i and break elsif converter == :date && value.match?(/[0-9]{2,4}/) begin value = Date.parse(value) break rescue nil end end end value end end row = CSV::Row.new(headers, values) yield row end end # # On remonte de deux fois la longueur du tampon. Une fois pour # revenir au point de départ, une fois pour remonter à la # portion suivante, à partir de la position courante, évide- # ment # new_pos = file.pos - 2 * buffer_size if new_pos < 0 file.seek(new_pos) else file.seek(- 2 * buffer_size, IO::SEEK_CUR) end # # Si on se trouve à 0, on doit s'arrêter # break if file.pos <= 0 # puts "Nouvelle position dans le fichier : #{file.pos}".bleu end else # # Sans bloc fourni, on renvoie tout le code du fichier # # À vos risques et périls # self.readlines(path, **options).to_a.reverse self.foreach(path, **).reverse end end |
.readlines_backward_in_small_file(path, **options, &block) ⇒ Object
Lecture à l’envers dans un petit fichier
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/clir/CSV_extension.rb', line 180 def readlines_backward_in_small_file(path, **, &block) if block_given? self.foreach(path, **).reverse_each do |row| yield row end # liste2reverse = [] # self.readlines(path, **options).each { |row| liste2reverse << row } # liste2reverse.reverse.each do |row| # yield row # end else # Lecture toute simple de la table # return self.readlines(path, **options).to_a.reverse return self.foreach(path, **).reverse end end |