La diferencia entre el flujo de bytes de Java y el flujo de caracteres

Dirección original : https://www.cnblogs.com/DONGb/p/7844123.html

1. El concepto de flujo

Todos los datos del programa se transmiten o guardan en una secuencia. Cuando el programa necesita datos, debe usar la secuencia de entrada para leer los datos, y cuando el programa necesita guardar algunos datos, debe usar la secuencia de salida para completar.

La entrada y la salida en el programa se guardan en forma de flujo, y lo que se guarda en el flujo son en realidad todos los archivos de bytes.

2. Secuencia de bytes y secuencia de caracteres

Hay dos categorías principales para manipular el contenido del archivo en el paquete java.io: flujo de bytes y flujo de caracteres, ambos se dividen en operaciones de entrada y salida. Los datos de salida en la secuencia de bytes se realizan principalmente mediante OutputStream, la entrada es InputStream, la salida en la secuencia de caracteres se realiza principalmente mediante la clase Writer y la secuencia de entrada se realiza principalmente mediante la clase Reader. (Estas cuatro son clases abstractas).

Java.io, un paquete dedicado a las funciones de entrada y salida, se proporciona en java, que incluye: InputStream, OutputStream, Reader, Writer.

 InputStream y OutputStream, dos están diseñados para flujos de bytes, utilizados principalmente para tratar con bytes u objetos binarios.

Lector y escritor: dos están diseñados para flujo de caracteres (un carácter ocupa dos bytes) y se utilizan principalmente para procesar caracteres o cadenas.

La unidad de procesamiento de flujo de caracteres es un carácter Unicode de 2 bytes, que opera caracteres, matrices de caracteres o cadenas, respectivamente, mientras que la unidad de procesamiento de flujo de bytes es de 1 byte, que opera bytes y matrices de bytes. Por lo tanto, el flujo de caracteres está formado por la máquina virtual Java que convierte bytes en caracteres Unicode de 2 bytes como unidad de caracteres, ¡por lo que tiene mejor soporte para múltiples idiomas! Si se trata de archivos de audio, imágenes, canciones, utilice mejor el flujo de bytes; si está relacionado con el chino (texto), utilice mejor el flujo de caracteres.

 El almacenamiento de todos los archivos es un almacenamiento de bytes. No son los caracteres del archivo los que están reservados en el disco, sino que los caracteres se codifican primero en bytes y luego estos bytes se almacenan en el disco. Al leer un archivo (especialmente un archivo de texto), también se lee byte a byte para formar una secuencia de bytes.

El flujo de bytes se puede utilizar para cualquier tipo de objeto, incluidos los objetos binarios, mientras que el flujo de caracteres solo puede manejar caracteres o cadenas; 2. El flujo de bytes proporciona la función de procesar cualquier tipo de operación de E / S, pero no puede manejar directamente caracteres Unicode. El flujo de caracteres está bien.

El flujo de bytes es el más básico. Todas las subclases de InputStrem y OutputStream se utilizan principalmente para procesar datos binarios. Se procesa por bytes, pero en realidad, muchos datos son texto y también se propone el concepto de flujo de caracteres. Se procesa de acuerdo con la codificación de la máquina virtual, es decir, la conversión del juego de caracteres se realiza entre los dos mediante InputStreamReader, OutputStreamWriter para asociar, de hecho, mediante byte [] y String para asociar caracteres chinos en el desarrollo real. De hecho, es causado por la conversión inconsistente entre el flujo de caracteres y el flujo de bytes 

================== También podemos ver: ======= =====

El tipo de retorno del método read () de la clase Reader es int: el carácter leído como un entero (dos bytes en total 16 bits), que van de  0 a 65535  (0x00-0xffff), si el final de la secuencia ha sido alcanzado, luego devuelve -1

Aunque read () de inputStream también devuelve un int, dado que este tipo está orientado a bytes y un byte ocupa 8 bits, devuelve  un valor de int byte en el rango de  0 a 255 . Si no hay bytes disponibles porque se ha alcanzado el final de la secuencia, se devuelve el valor -1. Por lo tanto, para valores que no se pueden representar por 0-255, ¡debe usar un flujo de caracteres para leer! Por ejemplo, caracteres chinos.

3. Flujo de operación de lectura y escritura de flujo

Procedimientos de operación:

También hay pasos correspondientes para las operaciones de E / S en Java. Tomando las operaciones de archivo como ejemplo, el flujo de operaciones principal es el siguiente:

a Utilice la clase File para abrir un archivo

b Especifique la ubicación de la salida subclasificando el flujo de bytes o el flujo de caracteres

c Realizar operaciones de lectura / escritura

d Apague la entrada / salida

La operación de E / S es una operación de recursos, debe recordar cerrarla.

4. Uso específico del flujo de bytes

El flujo de bytes manipula principalmente datos de tipo byte, que están sujetos a una matriz de bytes.Las principales clases de operación son OutputStream y InputStream.

Flujo de salida de bytes: OutputStream, OutputStream es la clase principal más grande del flujo de salida de bytes en todo el paquete IO. La definición de esta clase es la siguiente:

public abstract class OutputStream extends Object implements Closeable,Flushable

De la definición anterior, podemos encontrar que esta clase es una clase abstracta. Si desea usar esta clase, primero debe instanciar el objeto a través de una subclase. Si desea operar en un archivo, puede usar la clase FileOutputStream. Después de la conversión, puede crear una instancia de OutputStream

Closeable representa una operación que se puede cerrar, porque el programa debe cerrarse hasta el final

Desechable: significa actualizar, vaciar los datos en la memoria

El método de construcción de la clase FileOutputStream es el siguiente:

public FileOutputStream(File file)throws FileNotFoundException

Ejemplo de escritura de datos:

 
  1. import java.io.File;

  2. import java.io.FileOutputStream;

  3. import java.io.IOException;

  4. import java.io.OutputStream;

  5.  
  6. public class InputStreamStudy {

  7. public static void main(String[] args) throws IOException {

  8. File f = new File("d:" + File.separator+"test.txt");

  9. OutputStream out=new FileOutputStream(f);//如果文件不存在会自动创建

  10. String str="Hello World";

  11. byte[] b=str.getBytes();

  12. out.write(b);//因为是字节流,所以要转化成字节数组进行输出

  13. out.close();

  14. }

  15. }

Prueba de captura de pantalla:

También puede emitir byte por byte, de la siguiente manera:

 
  1. import java.io.File;

  2. import java.io.FileOutputStream;

  3. import java.io.IOException;

  4. import java.io.OutputStream;

  5.  
  6. public class InputStreamStudy {

  7. public static void main(String[] args) throws IOException {

  8. File f = new File("d:" + File.separator + "test.txt");

  9. OutputStream out = new FileOutputStream(f);//如果文件不存在会自动创建

  10. String str = "Hello World";

  11. byte[] b = str.getBytes();

  12. for (int i = 0; i < b.length; i++) {

  13. out.write(b[i]);

  14. }

  15. out.close();

  16. }

  17. }

Prueba de captura de pantalla:

La salida anterior solo se sobrescribirá; si desea agregarla, consulte otro constructor de la clase FileOutputStream:

public FileOutputStream(File file,boolean append)throws FileNotFoundException

En el método de construcción, si el valor de append se establece en verdadero, significa que el contenido se agrega al final del archivo.

 
  1. import java.io.File;

  2. import java.io.FileOutputStream;

  3. import java.io.IOException;

  4. import java.io.OutputStream;

  5.  
  6. public class InputStreamStudy {

  7. public static void main(String[] args) throws IOException {

  8. File f = new File("d:" + File.separator + "test.txt");

  9. OutputStream out = new FileOutputStream(f, true);//追加内容

  10. String str = "\r\nHello World";

  11. byte[] b = str.getBytes();

  12. for (int i = 0; i < b.length; i++) {

  13. out.write(b[i]);

  14. }

  15. out.close();

  16. }

  17. }

Ejecutar captura de pantalla:

Cambiar comportamiento en el archivo: \ r \ n

Flujo de entrada de bytes: InputStream

Ahora que el programa puede escribir contenido en el archivo, puede leer el contenido del archivo a través de InputStream. Primero, mire la definición de la clase InputStream:

public abstract class InputStream extends Object implements Closeable

Al igual que la clase OutputStream, InputStream en sí también es una clase abstracta y debe depender de sus subclases. Si está leyendo de un archivo, use FileInputStream para implementarlo.

Observe el método de construcción de la clase FileInputStream:

public FileInputStream(File file)throws FileNotFoundException

Ejemplos de lectura de archivos:

 
  1. import java.io.*;

  2.  
  3. public class InputStreamStudy {

  4. public static void main(String[] args) throws IOException {

  5. File f = new File("d:" + File.separator+"test.txt");

  6. InputStream in=new FileInputStream(f);

  7. byte[] b=new byte[1024];

  8. int len=in.read(b);

  9. in.close();

  10. System.out.println(new String(b,0,len));

  11. }

  12. }

Ejecutar captura de pantalla:

Pero el método anterior es problemático. Obviamente, es un desperdicio abrir una matriz de bytes tan grande. Podemos definir el tamaño de la matriz de bytes de acuerdo con el tamaño del archivo. El método en la clase File: public long length () .

 
  1. import java.io.*;

  2.  
  3. public class InputStreamStudy {

  4. public static void main(String[] args) throws IOException {

  5. File f = new File("d:" + File.separator+"test.txt");

  6. InputStream in=new FileInputStream(f);

  7. System.out.println(f.length());

  8. byte[] b=new byte[(int) f.length()];

  9. in.read(b);

  10. in.close();

  11. System.out.println(new String(b));

  12. }

  13. }

Ejecutar captura de pantalla:

Cambiemos la forma, leemos byte a byte ~

 
  1. import java.io.*;

  2.  
  3. public class InputStreamStudy {

  4. public static void main(String[] args) throws IOException {

  5. File f = new File("d:" + File.separator+"test.txt");

  6. InputStream in=new FileInputStream(f);

  7. byte[] b=new byte[(int) f.length()];

  8. for(int i=0;i<b.length;i++){

  9. b[i]=(byte) in.read();

  10. }

  11. in.close();

  12. System.out.println(new String(b));

  13. }

  14. }

Ejecutar captura de pantalla:

Pero la situación anterior solo es adecuada para conocer el tamaño del archivo de entrada, si no lo sabe, use el siguiente método:

 
  1. import java.io.*;

  2.  
  3. public class InputStreamStudy {

  4. public static void main(String[] args) throws IOException {

  5. File f = new File("d:" + File.separator+"test.txt");

  6. InputStream in=new FileInputStream(f);

  7. byte[] b=new byte[1024];

  8. int temp=0;

  9. int len=0;

  10. while((temp=in.read())!=-1){//-1为文件读完的标志

  11. b[len]=(byte) temp;

  12. len++;

  13. }

  14. in.close();

  15. System.out.println(new String(b,0,len));

  16. }

  17. }

Ejecutar captura de pantalla:

5. Uso específico del flujo de caracteres

En el programa, un carácter es igual a dos bytes, luego Java proporciona Reader y Writer dos clases especializadas para manipular secuencias de caracteres.

Flujo de salida de caracteres: escritor.

Writer en sí mismo es una clase de salida de flujo de caracteres, la definición de esta clase es la siguiente:

El escritor de clase abstracta pública extiende los implementos de objetos Appendable, Closeable, Flushable

Esta clase en sí también es una clase abstracta. Si desea usar esta clase, debe usar su subclase. Si desea escribir contenido en un archivo, debe usar una subclase FileWriter.

El método de construcción de la clase FileWriter se define de la siguiente manera:

public FileWriter(File file)throws IOException

La operación de flujo de caracteres es mejor que la operación de flujo de bytes, es decir, la cadena de caracteres se puede generar directamente y no es necesario realizar la operación de conversión como antes.

Escribir archivo:

 
  1. import java.io.*;

  2.  
  3. public class InputStreamStudy {

  4. public static void main(String[] args) throws IOException {

  5. File f = new File("d:" + File.separator + "test.txt");

  6. Writer out = new FileWriter(f);

  7. String str = "Hello 字符流";

  8. out.write(str);

  9. out.close();

  10. }

  11. }

Ejecutar captura de pantalla:

De forma predeterminada, la salida se sobrescribirá nuevamente, y el método de agregar es agregar una marca de agregar al constructor:

 
  1. import java.io.*;

  2.  
  3. public class InputStreamStudy {

  4. public static void main(String[] args) throws IOException {

  5. File f = new File("d:" + File.separator+"test.txt");

  6. Writer out=new FileWriter(f,true);//追加

  7. String str="\r\nHello 字符流";

  8. out.write(str);

  9. out.close();

  10. }

  11. }

Ejecutar captura de pantalla:

Flujo de entrada de caracteres: Lector

Reader usa caracteres para recuperar datos de archivos. La definición de la clase Reader es la siguiente:

public abstract class Reader extends Objects implements Readable,Closeable

El lector en sí también es una clase abstracta. Si desea leer el contenido de un archivo ahora, puede usar directamente la subclase FileReader.

El método de construcción de FileReader se define de la siguiente manera:

public FileReader(File file)throws FileNotFoundException

Lea los datos en forma de matriz de caracteres:

 
  1. import java.io.*;

  2.  
  3. public class InputStreamStudy {

  4. public static void main(String[] args) throws IOException {

  5. File f = new File("d:" + File.separator+"test.txt");

  6. Reader input=new FileReader(f);

  7. char[] c=new char[1024];

  8. int len=input.read(c);

  9. input.close();

  10. System.out.println(new String(c,0,len));

  11. }

  12. }

Ejecutar captura de pantalla:

También puede usar un bucle para determinar si leer hasta el final:

 
  1. import java.io.*;

  2.  
  3. public class InputStreamStudy {

  4. public static void main(String[] args) throws IOException {

  5. File f = new File("d:" + File.separator+"test.txt");

  6. Reader input=new FileReader(f);

  7. char[] c=new char[1024];

  8. int temp=0;

  9. int len=0;

  10. while((temp=input.read())!=-1){

  11. c[len]=(char) temp;

  12. len++;

  13. }

  14. input.close();

  15. System.out.println(new String(c,0,len));

  16. }

  17. }

Ejecutar captura de pantalla:

6. Resumen

El uso de la secuencia de bytes y la secuencia de caracteres son muy similares, así que además de la diferencia en el código de operación, ¿cuáles son las diferencias?

El flujo de bytes en sí mismo no usa el búfer (memoria) durante la operación, pero opera directamente con el archivo en sí, mientras que el flujo de caracteres usa el búfer durante la operación.

Cuando la secuencia de bytes está operando en el archivo, el archivo se puede generar incluso si el recurso no está cerrado (método de cierre), pero si la secuencia de caracteres no usa el método de cierre, no se generará nada, lo que indica que la secuencia de caracteres usa un búfer y se puede usar El método flush fuerza el búfer a vaciarse, y luego el contenido se puede sacar sin cerrar

Entonces, ¿es mejor usar flujo de bytes o flujo de caracteres en el desarrollo?

Al guardar archivos o transferir en todos los discos duros, se hace en bytes, las imágenes también se hacen en bytes, y los caracteres solo se forman en la memoria, por lo que la operación con bytes es la mayor parte.

Si desea que un programa Java implemente una función de copia, debe elegir un flujo de bytes para la operación (tal vez la copia sea una imagen) y usar el método de lectura y escritura (almacenamiento de memoria).

Supongo que te gusta

Origin blog.csdn.net/qq_30764991/article/details/103572619
Recomendado
Clasificación