34

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?

1
  • 1
    Why do you want to keep the \n. Can't you just assume its there? Commented Nov 1, 2009 at 17:41

14 Answers 14

46

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

String[] lines = StringUtils.split(FileUtils.readFileToString(new File("...")), '\n');
Sign up to request clarification or add additional context in comments.

1 Comment

+1 - trades one line of code for a dependency on Apache Commons IO and Lang.
33

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();
    }

3 Comments

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.
Another problem is that FileReader implictly picks up the whatever charset happens to be the default. Also the intermediate String is unnecessary.
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."
23

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!

3 Comments

This is probably the best answer!!
In most cases I would add a specific charset to the byte->char conversion: new String(..., someCharset).
Yeah, that's true. for example new String("", StandardCharsets.UTF_8)
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);
  }
}

7 Comments

+1 for simplest native solution. By the way, don't forget to prevent resource leak using scanner.close();
@mmdemirbas, OK I've added a complete example with resource and error handling. Thanks for the warning.
Scanner has a nasty bug when reading a different encoding than the one it is expecting, see: stackoverflow.com/questions/8330695/…
@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.
@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?
|
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]);

2 Comments

Or even leave it as an array.
or maybe leave the file alone altogether
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).

Comments

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;
}

Comments

2

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();

Comments

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();

6 Comments

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.
Ehmm, yes... Is this method deprecated? Oh, what does FYI mean?
FYI = For Your Information, one of the many common acronyms used on the Web.
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.
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.
|
1

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]);

Comments

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.

Comments

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.

Comments

0

You can try Cactoos:

import org.cactoos.io.TextOf;
import java.io.File;
new TextOf(new File("a.txt")).asString().split("\n")

Comments

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);
}
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.