开发者

Reading part of file with BufferedReader

开发者 https://www.devze.com 2023-01-25 09:08 出处:网络
I\'m trying to write a function that grabs a certain part of a file, sends that to another function, then continue to do the same thing from where the BufferedReader left offuntil the end of the file

I'm trying to write a function that grabs a certain part of a file, sends that to another function, then continue to do the same thing from where the BufferedReader left off until the end of the file but can't seem to figure out how to make it work.

Here is what I have:

String str = "";
int count = 0; 

 try {
  while(//condition so it loops through the entire file. I've tried fileReader.ready() and fileReader.read != -1 but both just run into infinite loops){

   while ((count <  4)){ 
    str += fileReader.read();
    count++;
    fileReader.mark(1000);
   }

   fileReader.reset();

   DoSomething(str) // send str to another function and do something with it;
  }
  } catch (IOException e) {
   // TODO Auto-generated catch block
  }

Can som开发者_运维问答eone help me with this and explain what I'm doing wrong? Much would be appreciated


If you know the number of characters, use the BufferedReader's .skip(long) method, which tells it to skip the first long characters (where long is a 64-bit whole number).

The call to skip will return a long with the number of characters actually skipped.


The mark() method marks position in the file and you can specify how many bytes you want to read before calling reset(), which would reposition stream to the marked point. So, normally you need to call mark() at the beginning of your data and then call reset before next iteration.

   while (count <  4){
    if(count>0) {
      fileReader.reset();
    }
    fileReader.mark(1000);
    str += fileReader.read();
    count++;
   }


The following works for me. Edited after comment.

import java.io.*;
public class Test {


public static void main(String[] args) {
String str = "";
int count = 0; 

try {
  Reader fileReader = new BufferedReader(new FileReader("testfile"));
  fileReader.mark(5);
 while(fileReader.ready()){
   count = 0;
   str ="";
   fileReader.reset();
  while (count <  4 && fileReader.ready()){ 
    if (count == 1){
      fileReader.mark(5);
    }
   str += (char)fileReader.read() ;
   count++;
  }

  System.out.println(str); // send str to another function and do something with it;

 }
 } catch (IOException e) {
  // TODO Auto-generated catch block
 }

}

}

Note that you need to cast fileReader.read(); to a char or you'll get wrong output, you have to reset the count otherwise count<4 won't be true ever after the first run (and since you don't do fileReader.read(), you'll get in an infitite loop), and you have to test for ready on each read (or you might block)

EDIT: Obviously, this is an example. You should never do the straight str += something in a loop, but use a StringBuffer, and catch and handle the possible exception.

Note on the second edit: if this is an intensive procedure, this is doing it wrong. I'll see if I can do it right (without backtracking)

YET ANOTHER EDIT:

import java.io.*;

public class Test {


  public static void main(String[] args) {
    StringBuffer buffer = new StringBuffer();
    int length = 4;

    try {
      Reader fileReader = new BufferedReader(new FileReader("teststring"));
      for (int i = 0; i < length && fileReader.ready(); i++) {
        buffer.append((char) fileReader.read());
      }

      while (fileReader.ready()) {
        System.out.println(buffer); // send str to another function and do
                                    // something with it;
        buffer.deleteCharAt(0);
        buffer.append((char) fileReader.read());

      }
      System.out.println(buffer); // send str to another function and do
                                 // something with it;
    }
    catch (IOException e) {
      // TODO Auto-generated catch block
    }

  }

}

The repeated call to the method that does something still isn't pretty, but this is a lot closer.


I think you just need to reset count = 0 after DoSomething(Str). Right now you're never resetting your count variable and it's preventing you from entering the file read loop.


Why mark and reset at all? Just read 4 bytes, process them, and repeat until EOF.


Based on Martijns answer I made the code a little simpler.

package so4168937;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

public class SecondTry {

  static void consume(Reader rd, int length) throws IOException {
    StringBuilder sb = new StringBuilder();
    int c;

    for (int i = 0; i < length - 1; i++) {
      if ((c = rd.read()) == -1)
        return;
      sb.append((char) c);
    }

    while ((c = rd.read()) != -1) {
      sb.append((char) c);
      System.out.println("<" + sb + ">");
      sb.deleteCharAt(0);
    }
  }

  public static void main(String[] args) throws IOException {
    consume(new StringReader("hi my name is joe"), 4);
  }

}

You don't need to use mark or reset, and using ready only adds complexity and unwanted behavior.


i see that most of you prefer to use the FileReader, as the question asked for, but i just prefer to use the Scanner instead because i find it easier to use. so here is my example:

import java.util.Scanner;
import java.io.File;
    private void fileReader(){
        String str;
        try {
            input = new Scanner(new File("FILENAME"));
        } catch (Exception e) {
            System.out.println("Scanner load failed.");
        }
        while(input.hasNext()){
            str+=input.next()+" ";
        }
        input.close();
        int j=0;
        for(int i=3;i<str.length();i++){
            DoSomething(str.substring(j,i));
            j++;
        }
    }

this reads each line and adds it to the string, and then it sends the string in bites of 4 to the DoSomething method.

i hope it helps.

Edit1: removed this edit.

Edit2:

did just read that you wanted in the comments.. and that can be done easily with any code actually i will change my code at the top to reflect this change.

hmm .. yeah.. that should work .. :)


My idea is to define a CharConsumer that defines what it means to consume a bunch of characters. Then I wrote a method that takes an arbitrary Reader and reads it until the end. If you want another terminating condition, replace the while (true) with it.

If you need the input to the consume method to be buffered, be sure that you create exactly one BufferedReader and don't use the other reader anymore after that. Otherwise some characters may get lost while reading.

package so4168937;

import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

public class Main {

  // unused, since the question was initially unclear
  public static void consumeFourInARow(Reader rd, CharConsumer consumer) throws IOException {
    char[] chars = new char[4];
    while (true) {
      for (int i = 0; i < chars.length; i++) {
        int c = rd.read();
        if (c == -1) {
          if (i == 0)
            return;
          throw new EOFException("Incomplete read after " + i + " characters.");
        }
        chars[i] = (char) c;
      }
      consumer.consume(chars);
    }
  }

  public static void consume(Reader rd, CharConsumer consumer) throws IOException {
    char[] chars = new char[4];
    int c;

    for (int i = 0; i < chars.length; i++) {
      if ((c = rd.read()) == -1) {
        return;
      }
      chars[i] = (char) c;
    }
    consumer.consume(chars);

    while ((c = rd.read()) != -1) {
      System.arraycopy(chars, 1, chars, 0, chars.length - 1);
      chars[chars.length - 1] = (char) c;
      consumer.consume(chars);
    }
  }

  interface CharConsumer {
    void consume(char[] chars);
  }

  public static void main(String[] args) throws IOException {
    final StringBuilder sb = new StringBuilder();
    consume(new StringReader("hi my name is joe..."), new CharConsumer() {
      @Override
      public void consume(char[] chars) {
        sb.append('<');
        sb.append(chars);
        sb.append('>');
      }
    });
    System.out.println(sb.toString());
  }

}

Update [2010-11-15]: Replaced the old code with code that implements a simple cyclic buffer, which is apparently what was wanted in the original question.

0

精彩评论

暂无评论...
验证码 换一张
取 消