web-dev-qa-db-fra.com

java entrée de fichier avec la capacité rewind () / reset ()

J'ai besoin d'écrire une fonction qui accepte une sorte de flux d'entrée (par exemple, un InputStream ou un FileChannel) afin de lire un gros fichier en deux passes: une fois pour précalculer certaines capacités, et deuxièmement pour faire le "vrai" travail. Je ne veux pas que le fichier entier soit chargé en mémoire à la fois (sauf s'il est petit).

Y a-t-il une classe Java classe qui fournit cette capacité? FileInputStream elle-même ne prend pas en charge mark ()/reset (). BufferedInputStream le fait, je pense, mais je suis pas clair s'il doit stocker le fichier entier pour ce faire.

C est si simple que vous utilisez simplement fseek (), ftell () et rewind (). :-(

33
Jason S

Je pense que les réponses faisant référence à un FileChannel sont sur la marque.

Voici un exemple d'implémentation d'un flux d'entrée qui encapsule cette fonctionnalité. Il utilise la délégation, donc ce n'est pas un vrai FileInputStream, mais c'est un InputStream, ce qui est généralement suffisant. On pourrait également étendre FileInputStream si c'est une exigence.

Non testé, utilisez à vos risques et périls :)

public class MarkableFileInputStream extends FilterInputStream {
    private FileChannel myFileChannel;
    private long mark = -1;

    public MarkableFileInputStream(FileInputStream fis) {
        super(fis);
        myFileChannel = fis.getChannel();
    }

    @Override
    public boolean markSupported() {
        return true;
    }

    @Override
    public synchronized void mark(int readlimit) {
        try {
            mark = myFileChannel.position();
        } catch (IOException ex) {
            mark = -1;
        }
    }

    @Override
    public synchronized void reset() throws IOException {
        if (mark == -1) {
            throw new IOException("not marked");
        }
        myFileChannel.position(mark);
    }
}
25
ykaganovich

BufferedInputStream prend en charge mark en mettant le contenu en mémoire tampon. Il est préférable de le réserver à des anticipations relativement petites d'une taille prévisible.

Au lieu de cela, RandomAccessFile peut être utilisé directement, ou il pourrait servir de base à un InputStream concret, étendu avec une méthode rewind().

Alternativement, un nouveau FileInputStream peut être ouvert pour chaque passage.

22
erickson

Si vous obtenez le FileChannel associé à partir du FileInputStream, vous pouvez utiliser la méthode position pour définir le pointeur de fichier n'importe où dans le fichier.

FileInputStream fis = new FileInputStream("/etc/hosts");
FileChannel     fc = fis.getChannel();


fc.position(100);// set the file pointer to byte position 100;
19
SW-Eng

Java.nio.channels.FileChannel A une méthode position(long) pour remettre la position à zéro comme fseek () en C.

7
Arne Burmeister

RandomAccessFile est ce que vous voulez:

6
dfa

PushbackInputStream fonctionnera également, tant que vous savez combien de caractères vous souhaitez pouvoir rembobiner

2
CT Arrington

Découvrez Java.io.RandomAccessFile

2
Rich Seller

Ce que vous voulez, c'est RandomAccessFileInputStream - implémente InputStream interface avec mark/reset, recherche parfois basée sur RandomAccessFiles. Certaines implémentations existent qui pourraient faire ce dont vous avez besoin.

Un exemple complet avec les sources se trouve dans http://www.fuin.org/utils4j/index.html mais vous en trouverez beaucoup d'autres sur Internet et il est assez facile de coder si aucun ne correspond exactement.

2
user1857918

BufferedInputStream a mark(readlimit) et reset(). readlimit doit être plus grand que filesize pour rendre la marque valide. file.length()+1 est OK. Cela signifie que la marque est valide jusqu'à ce que readlimit octets soient lus, vous pouvez donc revenir en arrière par reset().

2
Byung Ahn