Annuaire d'articles
Introduction de base au flux IO
Vue d'ensemble des flux IO :
I représente l'entrée, qui est le processus de lecture des données du fichier du disque dur dans la mémoire, qui est appelée entrée et est responsable de la lecture.
O signifie sortie, qui est le processus des données du programme de mémoire de la mémoire à l'écriture sur le fichier du disque dur, appelé sortie, responsable de l'écriture.
Classification des flux IO :
Classé par sens :
- flux d'entrée
- flux de sortie
Selon la plus petite unité de données du flux, il est divisé en :
- Flux d'octets : peut exploiter tous les types de fichiers ( y compris l'audio, la vidéo, les images d'écran, etc. )
- Flux de caractères : ne peut fonctionner que sur des fichiers en texte brut ( y compris les fichiers java, les fichiers txt, etc. )
Pour résumer les quatre grandes catégories de flux :
Flux d'entrée d'octets : basé sur la mémoire, le flux dans lequel les données des fichiers/réseaux du disque sont lus dans la mémoire sous forme d'octets est appelé flux d'entrée d'octets.
Flux de sortie d'octets : basé sur la mémoire, le flux qui écrit les données de la mémoire dans un fichier disque ou un réseau en octets est appelé flux de sortie d'octets.
Flux d'entrée de caractères : basé sur la mémoire, le flux dans lequel les données des fichiers/réseaux du disque sont lus dans la mémoire sous forme de caractères est appelé flux d'entrée de caractères.
Flux de sortie de caractères : basé sur la mémoire, le flux qui écrit les données de la mémoire dans un fichier disque ou un support réseau en caractères est appelé flux de sortie de caractères.
Utilisation de flux d'octets
flux d'entrée d'octets de fichier
Créer un flux d'entrée d'octets
Flux d'entrée d'octets de fichier : implémentez la classe FileInputStream
Fonction : sur la base de la mémoire, lit les données du fichier disque dans la mémoire en octets.
Le constructeur est le suivant :
constructeur | illustrer |
---|---|
public FileInputStream (fichier fichier) | Créer un canal de flux d'entrée d'octets pour se connecter à l'objet de fichier source |
public FileInputStream(String pathname) | Créer un canal de flux d'entrée d'octets connecté au chemin du fichier source |
Exemple de code :
public static void main(String[] args) throws FileNotFoundException {
// 写法一: 创建字节输入流与源文件对象接通
InputStream inp = new FileInputStream(new File("/file-io-app/src/test.txt"));
}
public static void main(String[] args) throws FileNotFoundException {
// 写法二: 创建字节输入流管道与源文件路径接通
InputStream inp = new FileInputStream("/file-io-app/src/test.txt");
}
lire un octet à la fois
nom de la méthode | illustrer |
---|---|
lire() | Renvoie un octet à la fois, ou -1 s'il n'y a plus d'octets à lire |
Par exemple, le contenu du fichier Bloc-notes que nous lisons est : abcd123
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
int a = inp.read();
System.out.println(a); // 97
System.out.println((char) a); // a
// 一次输入一个字节
System.out.println(inp.read()); // 98
System.out.println(inp.read()); // 99
System.out.println(inp.read()); // 100
System.out.println(inp.read()); // 49
System.out.println(inp.read()); // 50
System.out.println(inp.read()); // 51
// 无字节可读返回-1
System.out.println(inp.read()); // -1
}
Nous pouvons parcourir les octets du fichier
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
int b;
while ((b = inp.read()) != -1) {
System.out.print((char) b); // abcd123
}
}
La lecture d'un octet à la fois pose les problèmes suivants
performances lentes
Le problème des caractères tronqués ne peut pas être évité lors de la lecture des caractères chinois.
lire un tableau à la fois
nom de la méthode | illustrer |
---|---|
lire (octet [] tampon) | Chaque fois qu'un tableau d'octets est lu, le nombre d'octets lus est renvoyé et -1 est renvoyé s'il n'y a plus d'octets lisibles. |
Définir un tableau d'octets pour recevoir le nombre d'octets lus
Par exemple, dans le code suivant, le contenu du fichier est : abcd123, trois octets sont lus à chaque fois, et chaque lecture écrasera le contenu du tableau précédent, mais la troisième lecture ne lit qu'un seul caractère, donc uniquement Écrase le premier élément du tableau de caractères lu la dernière fois, le résultat est : 312
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
// 定义一个长度为3的字节数组
byte[] arr = new byte[3];
// 第一次读取一个字节数组
int len1 = inp.read(arr);
System.out.println("读取字节数: " + len1); // 读取字节数: 3
// 对字节数组进行解码
String res1 = new String(arr);
System.out.println(res1); // abc
// 第二次读取一个字节数组
int len2 = inp.read(arr);
System.out.println("读取字节数: " + len2); // 读取字节数: 3
// 对字节数组进行解码
String res2 = new String(arr);
System.out.println(res2); // d12
// 第三次读取一个字节数组
int len3 = inp.read(arr);
System.out.println("读取字节数: " + len3); // 读取字节数: 1
// 对字节数组进行解码
String res3 = new String(arr);
System.out.println(res3); // 312
// 无字节可读返回-1
System.out.println(inp.read()); // -1
}
Le deuxième paramètre de String peut spécifier la position de début et le troisième paramètre peut spécifier la position de fin. Ces deux paramètres peuvent être utilisés pour résoudre les inconvénients de la troisième lecture
Et la boucle améliore le code optimisé
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
byte[] arr = new byte[3];
int len;
while ((len = inp.read(arr)) != -1) {
String res = new String(arr, 0, len);
System.out.print(res); // abcd123
}
}
Les inconvénients de lire un tableau à la fois :
Les performances de lecture ont été améliorées
Le problème des caractères tronqués ne peut pas être évité lors de la lecture des caractères chinois.
Lire tous les octets à la fois
Pour résoudre le problème des caractères chinois brouillés, nous pouvons définir un tableau d'octets aussi grand que le fichier et lire tous les octets du fichier en une seule fois.
Inconvénient : si le fichier est trop volumineux, le tableau d'octets peut provoquer un débordement de mémoire.
Par exemple, lisez un fichier comme celui présenté ci-dessous
Méthode 1 :
Définissez vous-même un tableau d'octets aussi grand que la taille du fichier, puis utilisez la méthode de lecture du tableau d'octets pour terminer la lecture unique.
public static void main(String[] args) throws Exception {
File file = new File("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
InputStream inp = new FileInputStream(file);
// 创建一个与文件大小一样的字节数组
byte[] arr = new byte[(int) file.length()];
// 读取文件, 获取读取的字节长度
int len = inp.read(arr);
System.out.println(len); // 252
// 对字节数组进行解码
String res = new String(arr);
System.out.println(res);
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
}
Méthode 2 :
L'officiel fournit l'API suivante pour le flux d'entrée d'octets InputStream, qui peut directement lire toutes les données du fichier dans un tableau d'octets
nom de la méthode | illustrer |
---|---|
readAllBytes() | Lire directement toutes les données d'octets de l'objet fichier correspondant au flux d'entrée d'octets actuel, puis les charger dans un tableau d'octets et revenir |
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
// 获取文件的全部字节, 并返回一个字节数组
byte[] arr = inp.readAllBytes();
// 对字节数组进行解码
String res = new String(arr);
System.out.println(res);
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
// abcd123我爱Java学习Java.abcd123我爱Java学习Java.abcd123我爱Java学习Java.
}
flux de sortie d'octets de fichier
Créer un flux de sortie d'octets
Flux de sortie d'octets de fichier : implémentez la classe FileOutputStream
Fonction : sur la base de la mémoire, les données de la mémoire sont écrites sur le fichier disque sous forme d'octets.
Le constructeur est le suivant :
constructeur | illustrer |
---|---|
FileOutputStream(Fichier fichier) | Créer un canal de flux de sortie d'octets connecté à l'objet de fichier source |
FileOutputStream (chemin du fichier de chaîne) | Créer un canal de flux de sortie d'octets connecté au chemin du fichier source |
public static void main(String[] args) throws Exception {
// 写法一: 创建输出流与源文件对象接通
OutputStream oup = new FileOutputStream(new File("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt"));
}
public static void main(String[] args) throws Exception {
// 写法二: 创建输出与源文件路径接通(常用)
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
}
écrire dans le flux de sortie du fichier
API pour écrire des données à partir du flux de sortie d'octets du fichier :
nom de la méthode | illustrer |
---|---|
écrire (int a) | écrire un octet |
écrire (octet [] tampon) | écrire un tableau d'octets |
écriture(byte[] buffer , int pos , int len) | Écrire une partie d'un tableau d'octets. |
Actualisation du flux et fermeture de l'API :
méthode | illustrer |
---|---|
affleurer() | Actualiser le flux et continuer à écrire des données |
Fermer() | Fermez le flux, en libérant des ressources, mais en vidant le flux avant de fermer . Une fois fermées, les données ne peuvent plus être écrites |
Remarque : Les données doivent être actualisées lors de l'écriture des données et le flux doit être fermé après son utilisation.
écrire un octet
public static void main(String[] args) throws Exception {
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
oup.write('a');
// 支持写入编码
oup.write(97);
// 汉字占三个字节, 所以该方法不可以写入汉字
// oup.write('我');
// 写数据必须刷新数据
oup.flush();
// 刷新流后可以继续写入数据
oup.write('b');
// 使用完后需要关闭流, 关闭后不能再写入数据
oup.close();
}
écrire un tableau d'octets
public static void main(String[] args) throws Exception {
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
// 定义一个字节数组
byte[] arr = {
'a', 98, 'b', 'c'};
// 写入中文, 需要将中文编码成字节数组
byte[] chinese = "中国".getBytes();
// 写入英文字节数组
oup.write(arr);
// 写入中文字节数组
oup.write(chinese);
// 关闭流(关闭之前会刷新)
oup.close();
}
écrire une partie d'un tableau d'octets
public static void main(String[] args) throws Exception {
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
// 定义一个字节数组
byte[] arr = {
'a', 98, 'b', 'c'};
// 写入数组的第二个和第三个元素
oup.write(arr, 1, 2);
// 关闭流(关闭之前会刷新)
oup.close();
}
Connaissances supplémentaires :
Supplément 1 : lors de l'écriture de contenu, si vous devez modifier la ligne, vous pouvez la convertir
\r\n
( la fenêtre prend en charge l'entrée \n mais certains systèmes ne la prennent pas en charge, utilisez \r\n pour plus de polyvalence ) en un tableau d'octets et écrivez-le pour obtenir l'effet du saut de ligne
public static void main(String[] args) throws Exception {
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt");
// 定义一个字节数组
byte[] arr = {
'a', 98, 'b', 'c'};
oup.write(arr);
// 写入换行
oup.write("\r\n".getBytes());
// 写入数组的第二个和第三个元素
oup.write(arr, 1, 2);
// 关闭流(关闭之前会刷新)
oup.close();
}
Supplément 2 : lors de l'écriture d'un fichier, le fichier d'origine sera d'abord effacé, puis de nouvelles données seront écrites. Si nous voulons ajouter de nouvelles données basées sur les données du fichier d'origine, nous devons définir le deuxième paramètre du jeu de constructeurs vrai
constructeur | illustrer |
---|---|
FileOutputStream (fichier, ajout booléen) | Créez un pipeline de flux de sortie d'octets connecté à l'objet de fichier source et les données peuvent être ajoutées |
FileOutputStream(String filepath,boolean append) | Créez un pipeline de flux de sortie d'octets connecté au chemin du fichier source et les données peuvent être ajoutées |
public static void main(String[] args) throws Exception {
// 设置为true即可
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.txt", true);
}
exercice de copie de fichier
Exigences :
Copiez le fichier test.pdf dans le fichier newtest.pdf dans un autre répertoire
Analyse d'idée :
Créer un objet de flux d'entrée d'octets à partir d'une source de données
Créer un objet de flux de sortie d'octets basé sur la destination
Lire et écrire des données, copier une vidéo
libérer des ressources
Exemple de code :
public static void main(String[] args) {
try {
// 创建要复制文件的字节输入流
InputStream inp = new FileInputStream("/Users/chenyq/Documents/learn_Java/code/file-io-app/src/test.pdf");
// 创建目标路径的字节输出流
OutputStream oup = new FileOutputStream("/Users/chenyq/Documents/newtest.pdf");
// 使用文件输入流获取要复制文件的全部数据的字节数组
byte[] arr = inp.readAllBytes();
// 使用文件输出流将字节数组写入目标文件
oup.write(arr);
System.out.println("复制成功!");
// 释放资源
inp.close();
oup.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Question : Quels types de fichiers les flux d'octets peuvent-ils copier ?
La couche inférieure de tout fichier est constituée d'octets et la copie est un transfert mot à mot d'octets. Tant que le format et l'encodage des fichiers précédents et suivants sont cohérents, il n'y a pas de problème.
Résumé : le flux d'octets convient à la copie de fichiers, mais ne convient pas à la sortie en chinois