2

I have to read a file and depending of the content of the last lines, I have to copy most of its content into a new file. Unfortunately I didn't found a way to copy first n lines or chars of a file in java.
The only way I found, is copying the file using nio FileChannels where I can specifiy the length in bytes. However, therefore I would need to know how many bytes the stuff I read needed in the source-file.

Does anyone know a solution for one of these problems?

tshepang
  • 12,111
  • 21
  • 91
  • 136
user3479074
  • 131
  • 1
  • 3
  • 9
  • *copy first n lines or chars of a file*, please confirm again what is needed lines or chars? – Braj Aug 06 '14 at 19:49
  • You could use a `BufferedReader` and read N lines which you will write into a fileX. Then redo this process until you've splitted your file into several files. – Luiggi Mendoza Aug 06 '14 at 19:49
  • Would a BufferedReader.readLine() suffice, where invoked N times? – Mark W Aug 06 '14 at 19:49
  • Sorry for expressing ambiguous
    The file to read contains only simple text. If I have to specify the number of lines or the number of chars to copy doesn't really matter (I can count both while reading the file).
    Reading the file and write the needed content to another file would be possible but also slower than using another way of copying (like path, FileChannels...) and its important to copy as fast as possible
    – user3479074 Aug 06 '14 at 20:02

2 Answers2

1

You should use a BufferedReader and read N lines which you will write into a fileX. Then redo this process until you've splitted your file into several files.

Here's a basic example:

BufferedReader bw = null;
try (BufferedReader br = new BufferedReader(new FileReader(new File("<path_to_input_file>")))) {
    String line = "";
    StringBuilder sb = new StringBuilder();
    int count = 0;
    bw = new BufferedWriter(new FileWriter(new File("<path_to_output_file>")));
    while ( (line = br.readLine()) != null) {
        sb.append(line)
           .append(System.getProperty("line.separator"));
        if (count++ == 1000) {
            //flush and close current content into the current new file
            bw.write(sb.toString());
            bw.flush();
            bw.close();
            //start a new file
            bw = new BufferedWriter(new FileWriter(new File("<path_to_new_output_file>")));
            //re initialize the counter
            count = 0;
            //re initialize the String content
            sb = new StringBuilder();
        }
    }
    if (bw != null && sb.length() > 0) {
        bw.write(sb.toString());
        bw.flush();
        bw.close();
    }
} catch (Exception e) {
    e.printStacktrace(System.out);
}

Since you have performance as key quality attribute, use BufferedReader over Scanner. Here's an explanation about the performance comparison: Scanner vs. BufferedReader

Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • thx, but as mentioned above that wouldn't be as fast as using a way like nio.path or FileChannel, what is important in my case – user3479074 Aug 06 '14 at 20:08
  • 1
    @user3479074 sorry, you can't. You just have to work with what you have. Also, to check if it gives the performance you're looking for, you first have to test it, measure the results and compare against your time metrics, and you haven't posted anything related to this so we could do the comparison. – Luiggi Mendoza Aug 06 '14 at 20:10
  • Concerning the performance of the different methods I regarded a benchmark (http://baptiste-wicht.com/posts/2010/08/file-copy-in-java-benchmark.html) I found – user3479074 Aug 06 '14 at 20:15
  • @user3479074 they talk about copying entire files. Your current need seems to be to split a file into several (two or more) files, and you cannot do that with plain nio. Use what you have at your hands instead. – Luiggi Mendoza Aug 06 '14 at 20:16
  • I don't need to split the file, I only need to copy a part of it into a new one. The rest of the file can be thrown away – user3479074 Aug 06 '14 at 20:18
  • 1
    @user3479074 then you should calculate how many bytes you need to copy from one file to another. If you want to work with number of lines, then you don't have another choice but to use `BufferedReader`. – Luiggi Mendoza Aug 06 '14 at 20:21
  • If i do understand in a ideal world you would like something like 1.- Access last line in O(1). 2.- Copy a subset of correlative lines of the file to another one as fast as binary copy. ? – Diego Andrés Díaz Espinoza Aug 06 '14 at 21:51
  • 2
    @DiegoAndrésDíazEspinoza in an ideal world, we would only have a single programming language and a single OS with a single hardware architecture where this work would be done in a single LOC :) – Luiggi Mendoza Aug 06 '14 at 21:55
  • he he of course...anyway i was asking if @user3479074 really really really expect something like that – Diego Andrés Díaz Espinoza Aug 06 '14 at 22:18
  • @DiegoAndrésDíazEspinoza I guess OP needs a method to bulk copy a bunch limited quantity of bytes from a file into another but OP doesn't know how many bytes to copy so he/she want to perform this job w/o analyzing the content in the file. And this, sadly, cannot be done with plain Java NIO. – Luiggi Mendoza Aug 06 '14 at 22:19
  • @LuiggiMendoza sorry my ignorance i'm newbie on this, but can it done with another library? – Diego Andrés Díaz Espinoza Aug 06 '14 at 22:21
  • @DiegoAndrésDíazEspinoza yes, with `java.util.Scanner` or with `java.io.BufferedReader`. You could also rewrite such buffers and create a custom buffer to support this. – Luiggi Mendoza Aug 06 '14 at 22:22
  • @Diego Andrés Díaz Espinoza: 1.- No I have to read the entire file 2.- Yes =) – user3479074 Aug 07 '14 at 06:13
  • @LuiggiMendoza: How can I calculate the number of bytes in the source file? As far as I know I can't conclude it from the number of chars. – user3479074 Aug 07 '14 at 06:15
  • @user3479074 that's why you will fall back to this option as a possible solution... – Luiggi Mendoza Aug 07 '14 at 14:16
1

Try this:

Scanner scanner = new Scanner(yourFileObject); // initialise scanner

then

for (int i = 0; i < amountOfLines; i++) {
    String line = scanner.nextLine(); // get line excluding \n at the end
    // handle here
}

OR, for n chars, rather than lines:

Pattern charPattern = Pattern.compile(".")
// java.util.regex.Pattern with any char allowed
for (int i = 0; i < amountOfChars; i++) {
    char next = scanner.next(charPattern).toCharArray()[0];
    // handle here
}

This is, in my opinion, by far the best and easiest to write way to get the first n chars/lines from a file.

bcsb1001
  • 2,834
  • 3
  • 24
  • 35