Home > Blockchain >  Reading txt file in a formatted way to be printed back to user
Reading txt file in a formatted way to be printed back to user

Time:01-17

First, I have got this working but I'm trying to make it so it is able to be more versatile and handle more details in the txt file. The whole concept is the txt file is a file with album details and the code reads those details and prints them. But, i have only figured out how to get the code working only with 1 album in the file. I need the code to work even if there was 2, 3 or however many albums in the txt file without having to hard code(IO.readlines every specific line for each ablum) each album being read into the code. I have no idea how I can do that and really need help.

Essentially I have a txt file that looks like this:

Artist name1
Album name1
1
3
example1
sounds/01-example_1.wav
example2
sounds/06-example_2.wav
example3
sounds/20-example_3.wav

Now the concept is the 1st line is the artist name, 2nd line is the album title, 3rd is an integer which represents which genre it is (1 for example = pop etc.) and the 4th line represents how many songs there are.

The whole idea is to read this file and print the results like this:

Artist name1
Album name1
Genre is 1
Pop
example1
sounds/01-example_1.wav
example2
sounds/06-example_2.wav
example3
sounds/20-example_3.wav

The code i have is (not the whole file, just the important parts im trying to fix):

#Used to read and save the song name and location
def get_track(music_file)
  track_name = []
  track_location = []
  size = music_file.readlines.size
  line = 4
  while line < size
    line_1 = IO.readlines(music_file)[line]
    track_name.append(line_1)
    line  = 1
    line_2 = IO.readlines(music_file)[line]
    track_location.append(line_2)
    line  = 1
  end
  Track.new(track_name, track_location)
end

# Returns an array of tracks read from the given file using the integer in the txt file
def get_tracks(music_file)
      tracks = Array.new()
      count = IO.readlines(music_file)[3].to_i
      index = 0 
      while index < count
          track = get_track(music_file)
          tracks << track
          index  = 1
      end
      return tracks
  end

# Reads the artist name, album title and gets the genre integer
def read_album(music_file)
    tracks = get_tracks(music_file)
    album_title = IO.readlines(music_file)[1]
    album_artist = IO.readlines(music_file)[0]
    album_genre = IO.readlines(music_file)[2]
    album = Album.new(album_title, album_artist, album_genre, tracks)
    return album
end

This code only works with the file as it is but i need it to work if for example i added more albums in the text file so for example the file would look like this:

Artist name1
Album name1
1
3
example1
sounds/01-example_1.wav
example2
sounds/06-example_2.wav
example3
sounds/20-example_3.wav
Artist name2
Album name2
3
2
example1
sounds/01-example_1.wav
example2
sounds/06-example_2.wav

I need to change the code so that its able to read the file as if there was more than 1 album in the txt file instead of using the Readlines function to read every single different album.

CodePudding user response:

Your question looks okay, assuming that this is about right:

  • Your file contains multiple "chunks" or album data
  • Each "chunk" starts with a header of 4 rows, in a particular order
  • Each album then continues with a pair of rows for each track in the album (specified by the "track count" in the "header")
# Returns an array of tracks read from the given section of array
def get_tracks(track_arr)
  tracks = []
  track_arr.each_slice(2) do |name, location|
    tracks << Track.new(name, location)
  end
  tracks
end

# "shifts" the top 4 header rows, identifying the album, then
# loops through the remaining rows calculated from the song count
def get_album(music_arr)
  album_artist = music_arr.shift
  album_title = music_arr.shift
  album_genre = music_arr.shift.to_i
  track_count = music_arr.shift.to_i
  tracks = get_tracks(music_arr.shift(track_count * 2))

  Album.new(album_title, album_artist, album_genre, tracks)
end

# Reads the contents of the file, and loops through the albums found therein
def read_albums(music_file)
  albums=[]

  music_arr = music_file.readlines
  while music_arr.length > 0 do
    albums << get_album(music_arr)
  end

  albums
end

I was tempted to create a get_header routine, rather than just shifting the top 4 rows, or to change the routine to use an index value, and #range from the array, but if we're not processing the contents of the file further (i.e. it's disposable) then this is relatively fool-proof.

Output:

using:

Track = Struct.new(:track_name, :track_location)
Album = Struct.new(:album_title, :album_artist, :album_genre, :tracks)

and your second input file, we get output similar to:

[#<struct Album
  album_title="Album name1\n",
  album_artist="Artist name1\n",
  album_genre=1,
  tracks=
   [#<struct Track
     track_name="example1\n",
     track_location="sounds/01-example_1.wav\n">,
    #<struct Track
     track_name="example2\n",
     track_location="sounds/06-example_2.wav\n">,
    #<struct Track
     track_name="example3\n",
     track_location="sounds/20-example_3.wav\n">]>,
 #<struct Album
  album_title="Album name2\n",
  album_artist="Artist name2\n",
  album_genre=3,
  tracks=
   [#<struct Track
     track_name="example1\n",
     track_location="sounds/01-example_1.wav\n">,
    #<struct Track
     track_name="example2\n",
     track_location="sounds/06-example_2.wav\n">]>]

Edit:

A quick google search lead me to find that #readlines now takes chomp as an argument, which helps remove the nasty \n characters:

  music_arr = music_file.readlines(chomp: true)

output:

[#<struct Album
  album_title="Album name1",
  album_artist="Artist name1",
...
  •  Tags:  
  • ruby
  • Related