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 (). :-(
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);
}
}
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.
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;
Java.nio.channels.FileChannel
A une méthode position(long)
pour remettre la position à zéro comme fseek () en C.
RandomAccessFile est ce que vous voulez:
PushbackInputStream fonctionnera également, tant que vous savez combien de caractères vous souhaitez pouvoir rembobiner
Découvrez Java.io.RandomAccessFile
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.
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()
.