30

I have read a file into a String. The file contains various names, one name per line. Now the problem is that I want those names in a String array.

For that I have written the following code:

String [] names = fileString.split("\n"); // fileString is the string representation of the file

But I am not getting the desired results and the array obtained after splitting the string is of length 1. It means that the "fileString" doesn't have "\n" character but the file has this "\n" character.

So How to get around this problem?

Michał Kosmulski
  • 9,250
  • 1
  • 28
  • 46
Yatendra
  • 31,339
  • 88
  • 211
  • 291

14 Answers14

45

What about using Apache Commons (Commons IO and Commons Lang)?

String[] lines = StringUtils.split(FileUtils.readFileToString(new File("...")), '\n');
Romain Linsolas
  • 73,921
  • 45
  • 197
  • 265
29

The problem is not with how you're splitting the string; that bit is correct.

You have to review how you are reading the file to the string. You need something like this:

private String readFileAsString(String filePath) throws IOException {
        StringBuffer fileData = new StringBuffer();
        BufferedReader reader = new BufferedReader(
                new FileReader(filePath));
        char[] buf = new char[1024];
        int numRead=0;
        while((numRead=reader.read(buf)) != -1){
            String readData = String.valueOf(buf, 0, numRead);
            fileData.append(readData);
        }
        reader.close();
        return fileData.toString();
    }
b.roth
  • 8,919
  • 8
  • 33
  • 50
  • 8
    While correct I have a word of warning for anyone who sees this: I wouldn't use this exact code snippet since if IOException is thrown, the reader is never closed and may result in hanging FileReaders which can never be garbage collected which in *nix world means you will eventually run out of file handles and your JVM just simply crashes. – Esko Nov 01 '09 at 11:21
  • 5
    Another problem is that `FileReader` implictly picks up the whatever charset happens to be the default. Also the intermediate `String` is unnecessary. – Tom Hawtin - tackline Nov 01 '09 at 12:10
  • StringBuilder is probably a better choice than StringBuffer. From the StringBuffer javadoc: "As of release JDK 5, this class has been supplemented with an equivalentclass designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference tothis one, as it supports all of the same operations but it is faster, asit performs no synchronization." – Brent Sandstrom Jan 31 '19 at 18:40
17

As suggested by Garrett Rowe and Stan James you can use java.util.Scanner:

try (Scanner s = new Scanner(file).useDelimiter("\\Z")) {
  String contents = s.next();
}

or

try (Scanner s = new Scanner(file).useDelimiter("\\n")) {
  while(s.hasNext()) {
    String line = s.next();
  }
}

This code does not have external dependencies.

WARNING: you should specify the charset encoding as the second parameter of the Scanner's constructor. In this example I am using the platform's default, but this is most certainly wrong.

Here is an example of how to use java.util.Scanner with correct resource and error handling:

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.Iterator;

class TestScanner {
  public static void main(String[] args)
    throws FileNotFoundException {
    File file = new File(args[0]);

    System.out.println(getFileContents(file));

    processFileLines(file, new LineProcessor() {
      @Override
      public void process(int lineNumber, String lineContents) {
        System.out.println(lineNumber + ": " + lineContents);
      }
    });
  }

  static String getFileContents(File file)
    throws FileNotFoundException {
    try (Scanner s = new Scanner(file).useDelimiter("\\Z")) {
      return s.next();
    }
  }

  static void processFileLines(File file, LineProcessor lineProcessor)
    throws FileNotFoundException {
    try (Scanner s = new Scanner(file).useDelimiter("\\n")) {
      for (int lineNumber = 1; s.hasNext(); ++lineNumber) {
        lineProcessor.process(lineNumber, s.next());
      }
    }
  }

  static interface LineProcessor {
    void process(int lineNumber, String lineContents);
  }
}
Marcello Nuccio
  • 3,871
  • 25
  • 28
  • 1
    +1 for simplest native solution. By the way, don't forget to prevent resource leak using `scanner.close();` – mmdemirbas Feb 09 '13 at 09:01
  • 1
    @mmdemirbas, OK I've added a complete example with resource and error handling. Thanks for the warning. – Marcello Nuccio Apr 04 '13 at 08:02
  • Scanner has a nasty bug when reading a different encoding than the one it is expecting, see: https://stackoverflow.com/questions/8330695/java-scanner-not-going-through-entire-file – golimar Oct 24 '18 at 14:43
  • @golimar, the bug is in my own code: I should specify the charset as the second parameter of the Scanner's constructor, instead of relying on the default charset. – Marcello Nuccio Oct 24 '18 at 15:10
  • @MarcelloNuccio No, the problem is that when Scanner finds a character with a different encoding than the specified one (or default one), it exits returning a partial String (with a random size) and doesn't give any error or warning message – golimar Oct 25 '18 at 08:16
  • 1
    @golimar Agreed: error reporting in Scanner is buggy. But use of the wrong encoding to read a file is a bug in my own code. How can I read some text without knowing the characters' encoding? – Marcello Nuccio Oct 25 '18 at 09:28
  • @MarcelloNuccio True. However sometimes the only parts of the file that you need are ascii-only (e.g. a shell script with ascii-only commands and non-ascii comments that will be discarded) – golimar Oct 25 '18 at 11:07
15

Particularly i love this one using the java.nio.file package also described here.

You can optionally include the Charset as a second argument in the String constructor.

 String content = new String(Files.readAllBytes(Paths.get("/path/to/file")));
 

Cool huhhh!

Zuko
  • 2,276
  • 24
  • 27
8

You could read your file into a List instead of a String and then convert to an array:

//Setup a BufferedReader here    
List<String> list = new ArrayList<String>();
String line = reader.readLine();
while (line != null) {
  list.add(line);
  line = reader.readLine();
}
String[] arr = list.toArray(new String[0]);
starblue
  • 51,675
  • 14
  • 88
  • 146
leonm
  • 6,319
  • 27
  • 35
6

There is no built-in method in Java which can read an entire file. So you have the following options:

  • Use a non-standard library method, such as Apache Commons, see the code example in romaintaz's answer.
  • Loop around some read method (e.g. FileInputStream.read, which reads bytes, or FileReader.read, which reads chars; both read to a preallocated array). Both classes use system calls, so you'll have to speed them up with bufering (BufferedInputStream or BufferedReader) if you are reading just a small amount of data (say, less than 4096 bytes) at a time.
  • Loop around BufferedReader.readLine. There has a fundamental problem that it discards the information whether there was a '\n' at the end of the file -- so e.g. it is unable to distinguish an empty file from a file containing just a newline.

I'd use this code:

// charsetName can be null to use the default charset.
public static String readFileAsString(String fileName, String charsetName)
    throws java.io.IOException {
  java.io.InputStream is = new java.io.FileInputStream(fileName);
  try {
    final int bufsize = 4096;
    int available = is.available();
    byte[] data = new byte[available < bufsize ? bufsize : available];
    int used = 0;
    while (true) {
      if (data.length - used < bufsize) {
        byte[] newData = new byte[data.length << 1];
        System.arraycopy(data, 0, newData, 0, used);
        data = newData;
      }
      int got = is.read(data, used, data.length - used);
      if (got <= 0) break;
      used += got;
    }
    return charsetName != null ? new String(data, 0, used, charsetName)
                               : new String(data, 0, used);
  } finally {
    is.close();
  }
}

The code above has the following advantages:

  • It's correct: it reads the whole file, not discarding any byte.
  • It lets you specify the character set (encoding) the file uses.
  • It's fast (no matter how many newlines the file contains).
  • It doesn't waste memory (no matter how many newlines the file contains).
AlexWien
  • 27,247
  • 5
  • 48
  • 78
pts
  • 64,123
  • 15
  • 92
  • 159
3
FileReader fr=new FileReader(filename);
BufferedReader br=new BufferedReader(fr);
String strline;
String arr[]=new String[10];//10 is the no. of strings
while((strline=br.readLine())!=null)
{
arr[i++]=strline;
}
kiran
  • 31
  • 1
1

I always use this way:

String content = "";
String line;
BufferedReader reader = new BufferedReader(new FileReader(...));
while ((line = reader.readLine()) != null)
{
    content += "\n" + line;
}
// Cut of the first newline;
content = content.substring(1);
// Close the reader
reader.close();
Martijn Courteaux
  • 63,780
  • 43
  • 187
  • 279
  • 4
    FYI: Do you usually read small files with that code? I would have expected a significant performance hit with all that String concatenation... I'm don't mean to be negative, I am just curious. – Adam Paynter Nov 01 '09 at 10:49
  • Ehmm, yes... Is this method deprecated? Oh, what does FYI mean? – Martijn Courteaux Nov 01 '09 at 11:16
  • 1
    FYI = For Your Information, one of the many common acronyms used on the Web. – Esko Nov 01 '09 at 11:22
  • Why collect to a string instead of a list of strings one per each line? You usually need to do something with the collected data afterwards. – Thorbjørn Ravn Andersen Nov 01 '09 at 13:38
  • 3
    I guess the problem Adam was pointing to was that you do string concatenation += in a loop, which means you create a new String object every time (as Strings are immutable). This has quite a negative impact on performance. Use a StringBuilder (and do append()) instead of string for content. – Nicolai Nov 10 '09 at 13:57
  • Thanks for this hint. I will use this way in the futur. Now finally I get an anwser for that += operater and the new instance. Thanks – Martijn Courteaux Nov 10 '09 at 15:57
1

The simplest solution for reading a text file line by line and putting the results into an array of strings without using third party libraries would be this:

ArrayList<String> names = new ArrayList<String>();
Scanner scanner = new Scanner(new File("names.txt"));
while(scanner.hasNextLine()) {
    names.add(scanner.nextLine());
}
scanner.close();
String[] namesArr = (String[]) names.toArray();
bancer
  • 7,040
  • 7
  • 35
  • 57
0

A simpler (without loops), but less correct way, is to read everything to a byte array:

FileInputStream is = new FileInputStream(file);
byte[] b = new byte[(int) file.length()];  
is.read(b, 0, (int) file.length());
String contents = new String(b);

Also note that this has serious performance issues.

Anoyz
  • 6,603
  • 2
  • 26
  • 35
0

If you have only InputStream, you can use InputStreamReader.

SmbFileInputStream in = new SmbFileInputStream("smb://host/dir/file.ext");
InputStreamReader r=new InputStreamReader(in);
char buf[] = new char[5000];
int count=r.read(buf);
String s=String.valueOf(buf, 0, count);

You can add cycle and StringBuffer if needed.

Sae762
  • 36
  • 3
0

You can also use java.nio.file.Files to read an entire file into a String List then you can convert it to an array etc. Assuming a String variable named filePath, the following 2 lines will do that:

List<String> strList = Files.readAllLines(Paths.get(filePath), Charset.defaultCharset());
String[] strarray = strList.toArray(new String[0]);
Mike Szyndel
  • 9,787
  • 7
  • 41
  • 61
0

You can try Cactoos:

import org.cactoos.io.TextOf;
import java.io.File;
new TextOf(new File("a.txt")).asString().split("\n")
yegor256
  • 93,933
  • 106
  • 409
  • 558
0

Fixed Version of @Anoyz's answer:

import java.io.FileInputStream;
import java.io.File;

public class App {
public static void main(String[] args) throws Exception {

    File f = new File("file.txt");
    long fileSize = f.length();

    String file = "test.txt";

    FileInputStream is = new FileInputStream("file.txt");
    byte[] b = new byte[(int) f.length()];  
    is.read(b, 0, (int) f.length());
    String contents = new String(b);
}
}
Some guy
  • 11
  • 5