javaIO流知识点概况

一、前言:

1.1.流的概念:

java将输入与输出比喻为"流",英文:Stream. 就像生活中的"电流","水流"一样,它是以同一个方向顺序移动的过程.只不过这里流动的是字节(2进制数据).所以在IO中有输入流和输出流之分,我们理解他们是连接程序与另一端的"管道",用于获取或发送数据到另一端.

Java I/O 这里的I和O指的是输入与输出

输入:Input 用来读取数据的

输出:Output 用来写出数据的

1.2.IO流父类:

所有IO流的超类java.io.InputStreamjava.io.OutputStream

java.io.InputStream是所有字节输入流的超类,里面定义了所有字节输入流都必须具备的读取字节的方法

  • int read()

读取一个字节,以int形式返回,该int值的”低八位”有效,若返回值为-1则表示EOF

int read(byte[] data)

尝试最多读取给定数组的length个字节并存入该数组,返回值为实际读取到的字节量。

java.io.OutputStream是所有字节输出流的超类,里面定义了所有字节输出流都必须具备的写出字节的方法

void write(int d):写出一个字节,写的是给定的int的”低八位”

void write(byte[] data):将给定的字节数组中的所有字节全部写出

void write(byte[] data,int offset,int len):将给定的字节数组data中从offset处开始的连续len个字节写出

1.3.IO流分类概况:

(比如对人进行划分,依据性别划分,可以分为男人和女人。根据年龄段划分,可以分为未成年人,青年人,中年人,老年人)

  1. 根据输入和输出:  分为输入流和输出流
  2. 根据操作数据的内容划分为: 字节流和字符流

(字节流: FileInputStream和FileOutputStream、BufferedInputStream和BufferedOutputStream、ObjectInputStream和

ObjectoutputStream........)

(字符流:InputStreamReader和OutputStreamWriter、BufferReader和PrintWriter  .........)

  1. 根据是否能直接操作数据源: 分为节点流和处理流/或者低级流和高级流。

(节点流/低级流: FileInputStream和FileOutputStream ......... )

(处理流/高级流:BufferedInputStream和BufferedOutputStream、ObjectInputStream和

ObjectoutputStream、InputStreamReader和OutputStreamWriter、BufferReader和PrintWriter .........)    

二、低级流

低级流主要讲文件流

低级流中的文件流概念:  文件流是用来链接我们的程序与文件之间的"管道",用来读写文件数据的流。

文件流分为:

文件输入流java.io.FileInputStream:读取文件数据的流

文件输出流java.io.FileOutputStream:写入文件数据的流

注:文件流是继承自InputStream和OutputStream

2.1.文件输出流

java.io.FileOutputStream使用文件输出流向文件中写入数据

构造器:

FileOutputStream(String path)

创建文件输出流对指定的path路径表示的文件进行写操作,如果该文件不存在则将其创建出来

FileOutputStream(File file)

创建文件输出流对指定的file对象表示的文件进行写操作,如果该文件不存在则将其创建出来

              

2.1.1.写字节数据:
package com.zyq.io;
import java.io.FileOutputStream;
import java.io.IOException;
public class FOSDemo {
    public static void main(String[] args) throws IOException {
        //向当前项目目录下的文件fos.dat中写入数据
        //1.实例化FileOutputStream对象:
        FileOutputStream fos = new FileOutputStream("./src/com/zyq/io/fos.dat");
        //另一种实例化FileOutputStream对象的方式:
        //File file = new File("./fos.dat");
        //FileOutputStream fos = new FileOutputStream(file);
        /*
            void write(int d)
            用来向文件中写入1个字节(int数据的最后一个字节,最后8位二进制) 计算机底层只有2进制。1和0
         write方法会将给定的int值对应的2进制的"低八位"写出
         fos.write(1)

         write(2)
         int型2的2进制
         00000000 00000000 00000000 00000010
                                    ^^^^^^^^
                                    写出的数据

         fos.dat文件中内容:
         00000001 00000010
         */
	fos.write(97);
	fos.write(98);
        //当IO操作完毕后要关闭
        fos.close();
    }
}

文件内容: 写入了字符a和字符b对应的编码数据。

2.1.2.写文本数据

String提供方法: byte[] getBytes(String charsetName) 将当前字符串转换为一组字节

参数为字符集的名字,常用的是UTF-8。 其中中文字3字节表示1个,英文1字节表示1个。

String提供了将字符串转换为一组字节的方法

byte[] getBytes(Charset cs)将当前字符串按照指定的字符集转换为一组字节    

例如:String line = "在小小的花园里面";

byte[] data = line.getBytes(StandardCharsets.UTF_8);//将字符串按照UTF-8编码转换为一组字节

package aae_io;
import java.io.FileOutputStream;
import java.io.IOException;
public class FOS_WriteStr {/**向文件中写入文本数据*/
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("demo.txt");
        //fos的第一种写出方式:
        String str = "super idol的笑容都没你的甜,";
        byte[] data = str.getBytes("UTF-8");//str.getBytes(StandardCharsets.UTF_8);
        fos.write(data);
        //fos的第二种写出方式:
        fos.write("八月正午的阳光,都没你耀眼。".getBytes("UTF-8"));
        System.out.println("写出完毕!");
        fos.close();
    }
}

2.1.3.fos追加模式

重载的构造方法可以将文件输出流创建为追加模式

FileOutputStream(String path,boolean append)                   FileOutputStream(File file,boolean append)

当第二个参数传入true时,文件流为追加模式,即:指定的文件若存在,则原有数据保留,新写入的数据会被顺序的追加到文件中

FileOutputStream默认创建方式为覆盖模式,即:如果连接的文件存在,则会将该文件原有数据全部删除。然后将通过当前流写出的内容保存到文件中。
重载的构造方法允许我们再传入一个boolean型参数,如果这个值为true,则文件流为追加模式,即:若连接文件时该文件存在,原有数据全部保留,通过当前流写出的数据会顺序的追加到文件中。

package aae_io;
import java.io.FileOutputStream;
import java.io.IOException;
/**文件输出流FileOutputStream的追加写模式*/
public class FOS_FileAppend {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos =

             new FileOutputStream( "03_javaAPI/src/aae_io/FOS_FileAppend_demo.txt",true);
        fos.write("热爱105°的你,".getBytes("UTF-8"));
        fos.write("滴滴清纯的蒸馏水。".getBytes("UTF-8"));
        System.out.println("写出完毕!");
        fos.close();    

  }
}

2.2.文件输入流

             

java.io.FileInputStream使用文件输入流向从文件中读取数据

构造器

FileInputStream(String path):   基于给定的路径对应的文件创建文件输入流    

FileInputStream(File file):   基于给定的File对象所表示的文件创建文件输入流

2.2.1.基本用法:

基本用法如下:

package com.zyq.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class FISDemo {/**文件输入流 : 用于从文件中读取字节的流 */
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("./src/com/zyq/io/fos.dat");
         /*int read()
            读取1个字节,以int形式返回该字节内容。int值只有"低八位"有数据,高24位全部补0.
            有一个特殊情况:如果返回的int值为整数-1,则表示EOF。 EOF:end of file 文件末尾
            fos.dat文件数据:  01100001 01100010
            第一次调用:  int d = fis.read();
            01100001 01100010
            ^^^^^^^^
            读取的字节

            返回值d的二进制样子:
            00000000 00000000 00000000 01100001
            |-----自动补充的24个0------| 读取的字节 |

            第二次调用:
            d = fis.read();
            01100001 01100010
                     ^^^^^^^^
                     读取的字节

            返回值d的二进制样子:
            00000000 00000000 00000000 01100010
            |-----自动补充的24个0------| 读取的字节| 	

            第三次调用:
            d = fis.read();
            01100001 01100010
                              ^^^^^^^^
                              读取的字节
            返回值d的二进制样子:
            11111111 11111111 11111111 11111111
            |----------32位2进制都是1-----------|  */ 
        int d = fis.read();
        System.out.println(d);//97
        d = fis.read();
        System.out.println(d);//98
        d = fis.read();//文件只有2个字节,因此第三次读取已经是文件末尾EOF
        System.out.println(d);//-1
        fis.close();
    }
}
2.2.2读取文本数据
  1. String提供了将字节数组转换为字符串的构造方法:String(byte[]data,String charsetName): 将给定的字节数组中所有字节按照指定的字符集转换为字符串
  2. String(byte[]data,int offset,int len,String charsetName): 将给定的字节数组从下标offset处开始的连续len个字节按照指定的字符集转换为字符串

package aae_io;
import java.io.FileInputStream;
import java.io.IOException;
/**从文件中读取文本数据*/
public class FIS_ReadStr {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("03_javaAPI/src/aae_io/块读写.txt");
        byte[] data = new byte[1024];
        int len = fis.read(data);//块读操作
        System.err.println("实际读取到了"+len+"个字节");
        String line = new String(data,0,len,"UTF-8");
        System.err.println("字符个数"+line.length());
        System.out.println(line);
        fis.close();
    }
}

2.2.3.文件的复制

复制文件的经典案例

复制文件的原理就是使用文件输入流从原文件中陆续读取出每一个字节,然后再使用文件输出流将字节陆续写入到另一个文件中完成的。

示例代码

package io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/** * 文件的复制 */
public class CopyDemo {    
    public static void main(String[] args) throws IOException {         
        FileInputStream fis = new FileInputStream("image.jpg");//创建文件输入流读取原文件    
        FileOutputStream fos = new FileOutputStream("image_cp.jpg");//创建文件输出流写入复制文件       
        int d;//保存每次读取到的字节        
        /*原文件数据:  11000011 10101010 00001111 11001100 00110011 ...       
                      ^^^^^^^^            
        d = fis.read();   d:00000000 00000000 00000000 11000011 (读取文件的8位二进制)           
        fos.write(d);            
        image_cp.jpg文件的数据:    11000011 (只写出int数据的低八位<最后8位二进制>)  */      
        long start = System.currentTimeMillis();//获取当前系统时间的毫秒值(UTC时间)        
        while((d = fis.read()) != -1) {            
            fos.write(d);        
        }        
        long end = System.currentTimeMillis();//获取当前系统时间的毫秒值(UTC时间)        
        System.out.println("复制完毕!耗时:"+(end-start)+"ms");        
        fis.close();
        fos.close();    
    }
}     //结果: 复制完毕!耗时:61558ms

效率问题

上述案例在复制文件时的读写效率是很低的。因为硬盘的特性,决定着硬盘的读写效率差,而单字节读写就是在频繁调用硬盘的读写,从而产生了"木桶效应"。

为了解决这个问题,我们可以采取使用块读写的方式来复制文件,减少硬盘的实际读写的次数,从而提高效率。

2.2.4.文件的复制2

InputStream中定义了块读的方法: int read(byte[] data)

一次性读取给定字节数组总长度的字节量并存入到该数组中。 一次性从文件中读取给定的字节数组总长度的字节量,并存入到该数组中。 返回值为实际读取到的字节量。若返回值为-1则表示读取到了文件末尾。

块写操作 void write(byte[] data) 一次性将给定的字节数组所有字节写入到文件中

OutputStream中定义了块写的方法void write(byte[] data,int offset,int len) 块写:一次性将给定的字节数组从下标offset处开始的连续len个字节写入文件

package aae_io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**一次读取多个字节数据放入到byte数组: *
 * 通过提高每次读写的数据量,减少实际读写的次数,可以提高读写效率。
 * 单字节读写是一种随机读写形式。而一组一组字节的读写是块读写形式。*/
public class CopyDemo2 {
    public static void main(String[] args) throws IOException {
        //使用块读写形式完成文件复制
        //创建文件输入流读取原文件
        FileInputStream fis = new FileInputStream("./03_javaAPI/src/aae_io/7f.mp4");
        //创建文件输出流写复制文件
        FileOutputStream fos = new FileOutputStream("./03_javaAPI/src/aae_io/7f_2.mp4");
        int len;//记录每次实际读取的字节量
        byte[] data = new byte[1024*10];//10kb
        long start = System.currentTimeMillis();
        while((len = fis.read(data))!=-1){
            fos.write(data,0,len);//读取多少就写多少
        }
        long end = System.currentTimeMillis();
        System.out.println("复制完毕!耗时:"+(end-start)+"ms");
        fis.close();
        fos.close();
    }//复制完毕!耗时:50ms
}

注: 本案例要注意一个问题,如果用fos.write(data)写出数据,而不采用0,len两个参数则会导致有时最后一次写出时,会写出一些无效数据(导致复制成功的文件比原本的文件大一些<复制了倒数第二次剩余的一些数据>)

分析此过程:   第一次读取效果如下

第二次读取过程如下:

第三次读取过程如下:

第四次读取过程如下:

/* 常识:
    1byte=00000000   1字节为八位二进制
    1kb=1024byte
    1MB=1024kb
    1GB=1024MB*/

/* 块写操作
    void write(byte[] data)
    一次性将给定的字节数组所有字节写入到文件中
    void write(byte[] data,int offset,int len)
    一次性将给定的字节数组从下标offset处开始的连续len个字节写入文件
    1.假设文件数据如下:
    11001100 11110000 10101010 00001111 00110011
    ^^^^^^^^ ^^^^^^^^ ^^^^^^^^
    2.从文件中一次读取3个字节的数据:
    int d;
    byte[] data = new byte[3];//假设字节数组长度位3  //[00000000 00000000 00000000]

    3.第一次调用d=fis.read(data);
    d = fis.read(data);
    [11001100 11110000 10101010]
    d = 3 本次读取到了3个字节

    4.第二次调用d=fis.read(data);  读取情况如下:
    11001100 11110000 10101010 00001111 00110011
                               ^^^^^^^^ ^^^^^^^^
    d = fis.read(data);//仅读取了最后两个字节
    [00001111 00110011 10101010]//前两个字节为本次读取的内容(最后一个字节为第一次读取的数据<没有被清除>)
     ^^^^^^^^ ^^^^^^^^
    d = 2 本次读取到了2个字节
    5.第三次调用d=fis.read(data);读取情况如下;
    11001100 11110000 10101010 00001111 00110011 文件末尾!
                                                 ^^^^^^^^
    d = fis.read(data);//一个字节都没有读取到
    [00001111 00110011 10101010]数组没变化
    d = -1 文件末尾
 */

三、高级流

流连接示意图

java根据是否直接读写源数据,将IO分为了两类: 节点流(低级流)和处理流(高级流)

1.节点流:又称为"低级流",  特点:直接链接程序与另一端的"管道",是真实读写数据的流

IO一定是建立在节点流的基础上进行的。   文件流就是典型的节点流(低级流)

2.处理流:又称为"高级流"

特点:不能独立存在,必须链接在其他流上

目的:当数据经过当前高级流时可以对数据进行某种加工操作,来简化我们的同等操作

实际开发中我们经常"串联"一组高级流最终到某个低级流上,使读写数据以流水线式的加工处理完成。这一操作也被称为使"流的链接"。流链接也是JAVA IO的精髓所在。

3.1.缓冲流

java.io.BufferedOutputStream和BufferedInputStream: 缓冲流是一对高级流,作用是提高读写数据的效率.

缓冲流内部有一个字节数组,默认长度是8K. (缓冲流读写数据时, 是将数据的读写方式转换为块读写来保证读写效率)

功能:在流链接中的作用:加快读写效率,通常缓冲是最终链接在低级流上的流

构造器:

- 缓冲字节输出流

  BufferedOutputStream(OutputStream out):  实例化一个缓冲字节输出流并链接在指定的字节输出流上。默认缓冲区大小8kb(内部维护的byte[] buf数组长度8192)

  

  BufferedOutputStream(OutputStream out,int size):  实例化一个指定缓冲区大小的缓冲字节输出流并链接在指定的字节输出流上。

     

- 缓冲字节输入流

  BufferedInputStream(InputStream in)

  实例化一个缓冲字节输入流并链接在指定的字节输入流上。默认缓冲区大小8kb(内部维护的byte[] buf数组长度8192)

  

  BufferedInputStream(InputStream in,int size)

  实例化一个指定缓冲区大小的缓冲字节输入流并链接在指定的字节输入流上。    

  java将流按照是否直接能操作源数据,分为节点流与处理流两类
  1.节点流:也称为低级流,是真实连接程序与另一端的"管道",负责实际读写数据的流。
        读写一定是建立在节点流的基础上进行的。
        节点流好比家里的"自来水管"。连接我们的家庭与自来水厂,负责搬运水。
  2.处理流:也称为高级流,不能独立存在,必须连接在其他流上,目的是当数据经过当前流时
        对其进行某种加工处理,简化我们对数据的同等操作。
        高级流好比家里常见的对水做加工的设备,比如"净水器","热水器"。
        有了它们我们就不必再自己对水进行加工了。
  实际开发中我们经常会串联一组高级流最终连接到低级流上,在读写操作时以流水线式的加工
  完成复杂IO操作。这个过程也称为"流的连接"。
  缓冲流,是一对高级流(也叫处理流),作用是加快读写效率。
  java.io.BufferedInputStream和java.io.BufferedOutputStream

复制文件的经典案例

package aae_io;
import java.io.*;
public class BIS_CopyDemo1 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("ppt.pptx");
        BufferedInputStream bis = new BufferedInputStream(fis);
        FileOutputStream fos = new FileOutputStream("ppt_cp.pptx");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        int d;
        long start = System.currentTimeMillis();
        while((d = bis.read())!=-1){//使用缓冲流读取字节
            bos.write(d);//使用缓冲流写出字节
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-start)+"ms");
        bis.close();//关闭流时只需要关闭高级流即可,它会自动关闭它连接的流
        bos.close();
    }
}

内部定义了一个属性byte buf[]。它等同于我们之前练习复制案例时的块写操作。

并且默认创建时,该buf数组的长度为8192(8kb)长度。

缓冲流在读写数据时**总是以块读写数据**(默认是8kb)来保证读写效率的

缓冲流提供了多种构造器,可以自行指定缓冲区大小。

3.2.强制清空缓冲区

缓冲输出流写出数据时的缓冲区问题

缓冲流的flush方法用于强制将缓冲区中已经缓存的数据一次性写出。

注:该方法实际上实在字节输出流的超类OutputStream上定义的,并非只有缓冲输出流有这个方法。但是实际上只有缓冲输出流的该方法有实际意义,其他的流实现该方法的目的仅仅是为了在流连接过程中传递flush动作给缓冲输出流。

package aae_io;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class BOS_FlushDemo {

    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("bos.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        String line = "super idol的笑容都没你的甜~";
        byte[] data = line.getBytes(StandardCharsets.UTF_8);
        bos.write(data);
        System.out.println("写出完毕!");      
        bos.flush();//冲
        bos.close();
    }
}

flush的传递

flush()方法是被定义在java.io.Flushable中。而字节输出流的超类java.io.OutputStream实现了该接口,这意味着所有的字节输出流都有flush方法。而除了缓冲流之外的高级流的flush方法作用就是调用它链接的流的flush方法将该动作传递下去。最终传递给缓冲流来清空缓冲区。

复制文件的经典案例

所以给上边的复制案例添加flush之后如下:

package aae_io;
import java.io.*;
public class BIS_CopyDemo1 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("ppt.pptx");
        BufferedInputStream bis = new BufferedInputStream(fis);
        FileOutputStream fos = new FileOutputStream("ppt_cp.pptx");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        int d;
        long start = System.currentTimeMillis();
        while((d = bis.read())!=-1){//使用缓冲流读取字节
            bos.write(d);//使用缓冲流写出字节

            bos.flush();///
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-start)+"ms");
        bis.close();//关闭流时只需要关闭高级流即可,它会自动关闭它连接的流
        bos.close();
    }
}

3.3.对象流

java.io.ObjectInputStream和ObjectOutputStream

作用:  对象输出流:将我们的java对象进行序列化。对象输入流:将java对象进行反序列化·

序列化将一个对象转换为一组可被传输或保存的字节。这组字节中除了包含对象本身的数据外,还会包含结构信息。

序列化的意义实际开发中,我们通常会将对象写入磁盘,进行长久保存。在网络间两台计算机中的java间进行传输

无论是保存在磁盘中还是传输,都需要将对象转换为字节后才可以进行。

对象输出流的序列化操作void writeObject(Object obj)将给定的对象转换为一组可保存或传输的字节然后通过其链接的流将字节写出

例:

þ.对象输java.io.ObjectOutputStream  可以进行对象序列化

序列化要求对象输出流要求写出的对象必须实现接口:java.io.Serializable

案例中如果写出的对象Person没有实现java.io.Serializable时会抛出异常:NotSerializableException

对象输出流提供的序列化对象方法:  void writeObject(Object obj)
将给定的对象转换为一组可保存或传输的字节然后通过其链接的流将字节写出

案例:

package aae_io;
import java.io.*;/**对象流: 使用对象输出流完成对象序列化操作并最终保存到文件person.obj中*/
public class OOSDemo {
    public static void main(String[] args) throws IOException {
        Person p = new Person("王克晶");
        FileOutputStream fos = new FileOutputStream("person.obj");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(p);
        System.out.println("对象写出完毕");
        oos.close();
    }
}

class Person{
    String name;
    Person(String n){this.name=n;}
}


þ.对象输入流java.io.ObjectInputStream  可以进行对象反序列化

构造器ObjectInputStream(InputStream in)将当前创建的对象输入流链接在指定的输入流上  

反序列化方法:Object readObject()进行对象反序列化并返回。该方法会从当前对象输入流链接的流中读取若干字节并将其还原为对象。这里要注意读取的字节必须是由ObjectOutputStream序列化一个对象所得到的字节。

            

package aae_io;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

/**对象输入流,用来进行对象反序列化*/
public class OISDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //读取person.obj文件并将其中保存的数据进行反序列化
        FileInputStream fis = new FileInputStream("person.obj");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Person person = (Person)ois.readObject();
        System.out.println(person);
        ois.close();
    }
}

3.4.transient

当一个属性被transient关键字修饰后,该对象在进行序列化时,转换出来的字节中是不包含该属性的。忽略不必要的属性可以达到对象"瘦身"的操作。

对象瘦身可以在对象持久化时减少磁盘开销。在进行传输时可以缩短传输速度。

如果该对象不需要序列化,那么该关键字不发挥其他任何效果(也不需要使用这个关键字)

注意: 上边案例,序列化时不包含otherInfo属性,并且反序列化时该属性值为null

四、字符流:

  1. java将流按照读写单位划分为字节流与字符流.
  2. java.io.InputStream和OutputStream是所有字节流的超类
  3. 而java.io.Reader和Writer则是所有字符流的超类,它们和字节流的超类是平级关系.
  4. Reader和Writer是两个抽象类,里面规定了所有字符流都必须具备的读写字符的相关方法.
  5. 字符流最小读写单位为字符(char),但是底层实际还是读写字节,只是字符与字节的转换工作由字符流完成.
  6. 字符流都是高级流

4.1.超类:

4.1.1.java.io.Writer 所有字符输入流的超类

常用方法:  

void write(int c):写出一个字符,写出给定int值”低16”位表示的字符
void write(char[] chs):将给定字符数组中所有字符写出

void write(String str):将给定的字符串写出

void write(char[] chs,int offset,int len):将给定的字符数组中从offset处开始连续的len个字符写出。

4.1.2.java.io.Reader 所有字符输出流的超类

常用方法: 

int read():读取一个字符,返回的int值“低16”位有效。当返回值为-1时表达流读取到了末尾
int read(char[] chs):从该流中读取一个字符数组的length个字符并存入该数组,返回值为实际读取到的字符量。当返回值为-1时表达流读取到了末尾

4.2.转换流

java.io.InputStreamReader和OutputStreamWriter是常用的字符流的实现类作用为转换流

实际开发中我们通常不会直接用这两个流进行数据操作,但是他们在流连接中是必不可少的一环(连接字节流和字符流)

流连接中的作用·:  衔接字节流与其他字符流·,将字符与字节相互转换 。

意义:

实际开发中我们还有功能更好用的字符高级流.但是其他的字符高级流都有一个共通点:不能直接连接在字节流上.而实际操作设备的流都是低级流同时也都是字节流.因此不能直接在流连接中串联起来.转换流是一对可以连接在字节流上的字符流,其他的高级字符流可以连接在转换流上.在流连接中起到"转换器"的作用(负责字符与字节的实际转换)

4.2.1.转换输出流

OutputStreamWriter构造器

OutputStreamWriter(OutputStream out,Charset cs):基于给定的字节输出流以及字符编码创建OSW
OutputStreamWriter(OutputStream out):该构造方法会根据系统默认字符集创建OSW

案例: 注意通常不会直接用OutputStreamWriter直接操作文件。

package aae_io;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;

/**转换流写出文本数据:向文件osw.txt中写出文本数据*/
public class OSWDemo {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("osw.txt");
        OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
        osw.write("夜空中最亮的星,能否听清,");
        osw.write("那仰望的人心底的孤独和叹息。");
        System.out.println("写出完毕");
        osw.close();
    }
}

4.2.2.转换入流

构造器

InputStreamWriter(InputStream in,Charset cs): 基于给定的字节输入流以及字符编码创建当前转换流
InputStreamWriter(InputStream in): 该构造方法会根据系统默认字符集创建当前转换流

案例: 注意通常不会直接用InputStreamReader直接操作文件。

package aae_io;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**使用转换流读取文本数据*/
public class ISRDemo {
    public static void main(String[] args) throws IOException {
        //将osw.txt文件中的文本信息读取回来
        FileInputStream fis = new FileInputStream("osw.txt");
        InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
        //00000000 00000000 10011101 01110010
        int d;
        while(( d = isr.read()) != -1) {
            System.out.print((char) d);
        }
        isr.close();
    }
}

五、缓冲字符流:

5.1.缓冲字符输出流

缓冲字符输出流java.io.PrintWriter

  1. java.io.BufferedWriter和BufferedReader缓冲字符流内部也有一个缓冲区,读写文本数据以块读写形式加快效率.并且缓冲流有一个特别的功能:可以按行读写文本数据缓冲流内部维护一个char数组默认长度8192.以块读写方式读写字符数据保证效率
  2. java.io.PrintWriter具有自动行刷新的缓冲字符输出流,实际开发中更常用.它内部总是会自动连BufferedWriter作为块写加速使用

 工作原理

特点:

  1. - 可以按行写出字符串
  2. - 具有自动行刷新功能

PrintWriter的构造器

PrintWriter(File file)
PrintWriter(String path)
    
还支持指定字符集
PrintWriter(File file,String csn)
PrintWriter(String path,String csn)  
    
上述构造器看似PW可以直接对文件进行操作,但是它是一个高级流,实际内部会进行流连接:
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),false);
如上面工作原理图

:

package aae_io;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
public class PrintWriterDemo {
    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
//        PrintWriter pw = new PrintWriter("pw.txt");
        PrintWriter pw = new PrintWriter("pw.txt", "UTF-8");
        pw.println("我祈祷拥有一颗透明的心灵,和会流泪的眼睛。");
        pw.println("给我再去相信的勇气,oh越过黄昏去拥抱你。");
        System.out.println("写出完毕");
        pw.close();
    }
}

其他构造器 (很少用)

PritWriter(Writer writer)将当前实例化的PrintWriter链接在指定的字符输出流上    

由于除了转换流外的其他字符流都不能直接连在字节流上,因此这个构造器内部会自动链接在BufferedWriter上
并且让BufferedWriter链接在转换流OutputStreamWriter上,最后再让转换流链接再指定的字节输出流上    


PrintWriter(OutputStream out)  将当前实例化的PrintWriter链接在指定的字节输出流上

:

因为PrintWriter底层封装了BufferedWriter,然后再封装了OutputStreamWriter最后封装了字节流

所以这种写法很少使用。

package aae_io;
import java.io.*;
import java.nio.charset.StandardCharsets;
/**自行完成流连接向文件写出字符串*/
public class PrintWriterDemo2 {
    public static void main(String[] args) throws FileNotFoundException {
        //负责:将写出的字节写入到文件中
        FileOutputStream fos = new FileOutputStream("pw2.txt");
        //负责:将写出的字符全部转换为字节(可以按照指定的字符集转换)
        OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
        //负责:块写文本数据(攒够8192个字符一次性写出)
        BufferedWriter bw = new BufferedWriter(osw);
        //负责:按行写出字符串
        PrintWriter pw = new PrintWriter(bw);
        pw.println("你停在了这条我们熟悉的街,");
        pw.println("把你准备好的台词全念一遍。");
        System.out.println("写出完毕");
        pw.close();
    }
}

PrintWriter自动行刷新:

PrintWriter支持自动行刷新,每当我们调用println方法写出一行内容后自动flush一次。

对应的构造器:  PritWriter(Writer writer,boolean autoflush)   如果第二个参数为true则开启自动行刷新

经典案例-即时录入并保存的记事本:

package aae_io;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
 /** 实现一个简易的记事本工具
 * 利用流连接
 * 在文件输出流上最终链接到PrintWriter上。
 * 然后将用户在控制台上输入的每一行字符串都可以按行写入到对应的文件中。
 * 当用户在控制台上单独输入"exit"时程序退出。*/
public class PrintWriterFlushDemo {
    public static void main(String[] args) throws FileNotFoundException {       
        FileOutputStream fos = new FileOutputStream("note.txt");//负责:将写出的字节写入到文件中
        //负责:将写出的字符全部转换为字节(可以按照指定的字符集转换)
        OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
        //负责:块写文本数据(攒够8192个字符一次性写出)
        BufferedWriter bw = new BufferedWriter(osw);        
        PrintWriter pw = new PrintWriter(bw,true);//负责:按行写出字符串//true开启自动行刷新
        Scanner scanner = new Scanner(System.in);
        System.out.println("请开始输入内容,单独输入exit退出");
        while(true){
            String line = scanner.nextLine();
            //String可以忽略大小写比较字符串内容:equalsIgnoreCase
            if("exit".equalsIgnoreCase(line)){ break;  }
            pw.println(line);//每当println后自动flush。注意:print方法并不会自动flush
        }
        System.out.println("再见!");
        pw.close();
    }
}

5.2.缓冲字符输入流:

缓冲字符输入流-java.io.BufferedReader

缓冲字符输入流内部维护一个默认8192长度的char数组,总是以块读取文本数据保证读取效率。

缓冲输入流提供了一个按行读取文本数据的方法

据的方法

String readLine()
返回一行字符串。方法内部会连续扫描若干个字符,直到遇到换行符为止,将换行符之前的内容以一个字符串形式返回。
返回的字符串中不含有最后的换行符。
返回值有三种情况:
1:正常一行内容
2:空字符串。当读取了一个空行时(这一行只有一个换行符)
3:null。当流读取到了末尾时。  
    
当我们第一次调用readLine()时,流并不是只读取了一行字符串,而是先进行块读操作(一次性读取8192个字符并转入到内部的char数组中),然后扫描内部的char数组,然后将第一行字符串返回。第二次调用后再继续扫描后去的内容以此类推。 

案例:

package aae_io;
import java.io.*;
/**使用缓冲字符输入流读取文本数据*/
public class BRDemo {
    public static void main(String[] args) throws IOException {
        //将当前源代码输出到控制台上
        FileInputStream fis = new FileInputStream(//1:创建文件输入流读取当前源代码文件
                "./src/main/java/io/BRDemo.java");
        InputStreamReader isr = new InputStreamReader(fis);//2.用InputStreamReader进行流连接
        BufferedReader br = new BufferedReader(isr);//2:最终链接到BufferedReader上
        String line;//3:读取每一行字符串并输出到控制台上
        while((line = br.readLine())!=null) {
            System.out.println(line);
        }
        br.close();
    }
}

六、总结:

6.1.File类

File类的每一个实例可以表示硬盘(文件系统)中的一个文件或目录(实际上表示的是一个抽象路径)

使用File可以做到:

1:访问其表示的文件或目录的属性信息,例如:名字,大小,修改时间等等

2:创建和删除文件或目录

3:访问一个目录中的子项

常用构造器:

File(String pathname)

File(File parent,String name)可参考文档了解

常用方法:

length():返回一个long值,表示占用的磁盘空间,单位为字节。

canRead():File表示的文件或目录是否可读

canWrite():File表示的文件或目录是否可写

isHidden():File表示的文件或目录是否为隐藏的

createNewFile():创建一个新文件,如果指定的文件所在的目录不存在会抛出异常java.io.FileNotFoundException

mkdir:创建一个目录

mkdirs:创建一个目录,并且会将所有不存在的父目录一同创建出来,推荐使用。

delete():删除当前文件或目录,如果目录不是空的则删除失败。

exists():判断File表示的文件或目录是否真实存在。true:存在 false:不存在

isFile():判断当前File表示的是否为一个文件。

isDirectory():判断当前File表示的是否为一个目录

listFiles():获取File表示的目录中的所有子项

listFiles(FileFilter filter):获取File表示的目录中满足filter过滤器要求的所有子项

6.2.JAVA IO必会概念:

java io可以让我们用标准的读写操作来完成对不同设备的读写数据工作.·

java将IO按照方向划分为输入与输出,参照点是我们写的程序.·

输入:用来读取数据的,是从外界到程序的方向,用于获取数据.·

输出:用来写出数据的,是从程序到外界的方向,用于发送数据.

java将IO比喻为"流",即:stream. 就像生活中的"电流","水流"一样,它是以同一个方向顺序移动的过程.只不过这里流动的是字节(2进制数据).故在IO中有输入流和输出流之分,理解他们是连接程序与另一端的"管道",用于获取或发送数据到另一端.

因此流的读写是顺序读写的,只能顺序向后写或向后读,不能回退。

6.3.字节流两个超类

Java定义了两个超类(抽象类):

java.io.InputStream:所有字节输入流的超类,其中定义了读取数据的方法.因此将来不管读取的是什么设备(连接该设备的流)都有这些读取的方法,因此我们可以用相同的方法读取不同设备中的数据

InputStream常用方法:

int read():读取一个字节,返回的int值低8位为读取的数据。如果返回值为整数-1则表示读取到了流的末尾


int read(byte[] data):块读取,最多读取data数组总长度的数据并从数组第一个位置开始存入到数组中,返回值表示实际读取到的字节量,如果返回值为-1表示本次没有读取到任何数据,是流的末尾。

java.io.OutputStream:所有字节输出流的超类,其中定义了写出数据的方法.

OutputStream常用方法:

void write(int d):写出一个字节,写出的是给定的int值对应2进制的低八位
void write(byte[] data):块写,将给定字节数组中所有字节一次性写出。

void write(byte[]data,int off,int len):块写,将给定字节数组从下标off处开始的连续len个字节一次性写出

6.4IO流的分类:

根据不同的划分依据,分类结果也不同

(比如对人进行划分,依据性别划分,可以分为男人和女人。根据年龄段划分,可以分为未成年人,青年人,中年人,老年人)

  1. 根据输入和输出:  分为输入流和输出流
  2. 根据操作数据的内容划分为: 字节流和字符流

(字节流: FileInputStream和FileOutputStream、BufferedInputStream和BufferedOutputStream、ObjectInputStream和

ObjectoutputStream........)

(字符流:InputStreamReader和OutputStreamWriter、BufferReader和PrintWriter  .........)

  1. 根据是否能直接操作数据源: 分为节点流和处理流/或者低级流和高级流。

(节点流/低级流: FileInputStream和FileOutputStream ......... )

(处理流/高级流:BufferedInputStream和BufferedOutputStream、ObjectInputStream和

ObjectoutputStream、InputStreamReader和OutputStreamWriter、BufferReader和PrintWriter .........) 

节点流:也称为低级流.

节点流的另一端是明确的,是实际读写数据的流,读写一定是建立在节点流基础上进行的.

处理流:也称为高级流.

处理流不能独立存在,必须连接在其他流上,目的是当数据流经当前流时对数据进行加工处理来简化我们对数据的该操作.

实际应用中,我们可以通过串联一组高级流到某个低级流上以流水线式的加工处理对某设备的数据进行读写,这个过程也成为流的连接,这也是IO的精髓所在.

6.5.文件流

文件流是一对低级流,用于读写文件的流。

6.5.1.文件输出流:

java.io.FileOutputStream文件输出流,继承自java.io.OutputStream

常用构造器:

覆盖模式的构造器覆盖模式是指若指定的文件存在,文件流在创建时会先将该文件原内容清除。

FileOutputStream(String pathname):创建文件输出流用于向指定路径表示的文件做写操作

FileOutputStream(File file):创建文件输出流用于向File表示的文件做写操作。

注:如果写出的文件不存在文件流自动创建这个文件,但是如果该文件所在的目录不存在会抛出异常:java.io.FileNotFoundException

追加写模式对应的构造器追加模式是指若指定的文件存在,文件流会将写出的数据陆续追加到文件中。

FileOutputStream(String pathname,boolean append):append为true追加模式,false则为覆盖模式

FileOutputStream(File file,boolean append):append为true追加模式,false则为覆盖模式

常用方法:

void write(int d):向文件中写入一个字节,写入的是int值2进制的低八位。​
void write(byte[] data):向文件中块写数据。将数组data中所有字节一次性写入文件。​
void write(byte[] data,int off,int len):向文件中快写数据。将数组data中从下标off开始的连续len个字节一次性写入文件。

6.5.2.文件输入流:

java.io.FileInputStream文件输入流,继承自java.io.InputStream

常用构造器

FileInputStream(String pathname) 创建读取指定路径下对应的文件的文件输入流,如果指定的文件不存在则会抛出异常java.io.FileNotFoundException

FileInputStream(File file) 创建读取File表示的文件的文件输入流,如果File表示的文件不存在则会抛出异常java.io.IOException。

常用方法

int read():从文件中读取一个字节,返回的int值低八位有效,如果返回的int值为整数-1则表示读取到了文件末尾。
int read(byte[] data):块读数据,从文件中一次性读取给定的data数组总长度的字节量并从数组第一个元素位置开始存入数组中。返回值为实际读取到的字节数。如果返回值为整数-1则表示读取到了文件末尾。

6.6缓冲流

缓冲流是一对高级流,在流链接中链接它的目的是加快读写效率。缓冲流内部默认缓冲区为8kb,缓冲流总是块读写数据来提高读写效率。

java.io.BufferedOutputStream缓冲字节输出流,继承自java.io.OutputStream

6.6.1.常用构造器

BufferedOutputStream(OutputStream out):创建一个默认8kb大小缓冲区的缓冲字节输出流,并连接到参数指定的字节输出流上。

BufferedOutputStream(OutputStream out,int size):创建一个size指定大小(单位是字节)缓冲区的缓冲字节输出流,并连接到参数指定的字节输出流上。

6.6.2.常用方法

flush():强制将缓冲区中已经缓存的数据一次性写出
缓冲流的写出方法功能与OutputStream上一致,需要知道的时write方法调用后并非实际写出,而是先将数据存入缓冲区(内部的字节数组中),当缓冲区满了时会自动写出一次。

6.6.3.java.io.BufferedInputStream缓冲字节输出流,继承自java.io.InputStream

6.6.4.常用构造器:

BufferedInputStream(InputStream in):创建一个默认8kb大小缓冲区的缓冲字节输入流,并连接到参数指定的字节输入流上。

BufferedInputStream(InputStream in,int size):创建一个size指定大小(单位是字节)缓冲区的缓冲字节输入流,并连接到参数指定的字节输入流上。

6.6.5.常用方法

缓冲流的读取方法功能与InputStream上一致,需要知道的时read方法调用后缓冲流会一次性读取缓冲区大小的字节数据并存入缓冲区,然后再根据我们调用read方法读取的字节数进行返回,直到缓冲区所有数据都已经通过read方法返回后会再次读取一组数据进缓冲区。即:块读取操作

6.7.对象流

对象流是一对高级流,在流链接中的作用是完成对象的序列化与反序列化

序列化:是对象输出流的工作,将一个对象按照其结构转换为一组字节的过程。

反序列化:是对象输入流的工作,将一组字节还原为对象的过程。

6.7.1.java.io.ObjectInputStream对象输入流,继承自java.io.InputStream

常用构造器

ObjectInputStream(InputStream in):创建一个对象输入流并连接到参数in这个输入流上。

常用方法

Object readObject():进行对象反序列化,将读取的字节转换为一个对象并以Object形式返回(多态)。

如果读取的字节表示的不是一个java对象会抛出异常:java.io.ClassNotFoundException

6.7.2.java.io.ObjectOutputStream对象输出流,继承自java.io.OutputStream

常用构造器

ObjectOutputStream(OutputStream out):创建一个对象输出流并连接到参数out这个输出流上

常用方法

void writeObject(Object obj):进行对象的序列化,将一个java对象序列化成一组字节后再通过连接的输出流将这组字节写出。

如果序列化的对象没有实现可序列化接口:java.io.Serializable就会抛出异常:java.io.NotSerializableException

6.8.Serrializable接口

序列化接口Serrializable

java.io.Serrializable没有任何抽象方法,但是只有实现了该接口的类的实例才能进行序列化与反序列化

实现了序列化接口的类建议显示的定义常量:static final long serialVersionUID = 1L;

可为属性添加关键字transient,被该关键字修饰的属性在序列化时会被忽略,达到对象序列化瘦身的目的

                                                            

By  zhaoyq  at  2024-05-28

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/655062.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【RabbitMQ】使用SpringAMQP的Publish/Subscribe(发布/订阅)

Publish/Subscribe **发布(Publish)、订阅(Subscribe)&#xff1a;**允许将同一个消息发送给多个消费者 **注意&#xff1a;**exchange负责消息路由&#xff0c;而不是存储&#xff0c;路由失败则消息丢失 常见的**X(exchange–交换机)***类型&#xff1a; Fanout 广播Direc…

SPP/BLE蓝牙双模方案,主从一体,串口速率可达85KB/S

MS-BTD020A是一款蓝牙5.0双模数传模块&#xff0c;支持SPP&#xff08;经典蓝牙&#xff09;和BLE&#xff08;低功耗蓝牙&#xff09;。蓝牙双模技术使其能够在传统蓝牙和低功耗蓝牙之间无缝切换&#xff0c;用户只需要进行简单的设置就可以实现串口与手机之间的无线传输。模块…

【每日一坑】KiCAD 覆铜区域约束

【每日一坑】 1.螺丝孔周围不想要要铜皮&#xff1b; 2、首先在CTRLshiftK;画一个区域&#xff0c;比如铺一个GND; 3、选择CUTOUT; 4、画线&#xff0c;画好闭合图形&#xff1b;如下图 5、就是这样了&#xff0c;就是还没有画圆或者异形的&#xff1b;

Scikit-Learn随机森林

Scikit-Learn随机森林 1、随机森林1.1、集成学习1.2、Bagging方法1.3、随机森林算法1.4、随机森林的优缺点2、Scikit-Learn随机森林回归2.1、Scikit-Learn随机森林回归API2.2、随机森林回归实践(加州房价预测)1、随机森林 随机森林是一种由决策树构成的集成算法,它在大多情况…

香橙派 AiPro通过Micro USB接口进行串口调试

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、配置步骤1.安装CH343驱动2.配置串口参数 二、使用步骤总结 前言 最近在玩一个新玩具香橙派 AiPro&#xff0c;除了通过SSH方式连接开发板以外&#xff0c;…

Llama模型家族训练奖励模型Reward Model技术及代码实战(二)从用户反馈构建比较数据集

LlaMA 3 系列博客 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;一&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;二&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;三&#xff09; 基于 LlaMA…

设计模式:外观模式 导诊台。空指针异常

文章目录 UML类图目录结构思路Register.javaOutpatientService.javaPrice.javaPharmacy.javaFacade.java空指针异常 Test.java UML类图 目录结构 思路 照着写&#xff0c;然后getRegister&#xff08;&#xff09;方法的具体实现就是&#xff1a;打印一句话&#xff0c;然后到…

服务器端口查询:一项至关重要的网络管理任务

在网络管理和系统维护中&#xff0c;服务器端口查询是一项至关重要的任务。服务器端口是网络通信的入口点&#xff0c;它们允许各种服务和应用程序在网络上进行交互。因此&#xff0c;准确而有效地查询服务器端口的状态和配置对于确保网络的安全性和稳定性至关重要。 首先&…

floodfill 算法(上)

目录 图像渲染 题意&#xff1a; 题解&#xff1a; 非递归&#xff1a; 递归&#xff1a; 岛屿数量 题解&#xff1a; 非递归&#xff1a; 递归&#xff1a; 岛屿的最大面积 题解&#xff1a; 非递归&#xff1a; 递归&#xff1a; 被围绕的区域 题解&#xff1a…

10G SFP双口万兆以太网控制器,高速光口网络接口卡

2-Port 10G SFP NIC 是一款高速网 络接口卡&#xff0c;采用了 PCI Express 3.0 x8 接口&#xff0c;支持双 端口万兆以太网&#xff0c;具有高性能、高可靠性、低功耗等 优点&#xff0c;是数据中心、云计算、虚拟化等领域的理想选 择。 支持多种网络协议&#xff0c;如 …

爱岗敬业短视频:成都科成博通文化传媒公司

爱岗敬业短视频&#xff1a;传递正能量&#xff0c;塑造职场新风尚 在当今社会&#xff0c;短视频以其独特的传播方式和广泛的受众群体&#xff0c;成为了信息传播的重要渠道。在众多短视频内容中&#xff0c;以“爱岗敬业”为主题的短视频尤为引人注目&#xff0c;成都科成博…

云衔科技:为什么推荐使用zoho crm客户管理系统?

在当今快速变化的商业环境中&#xff0c;企业对高效、智能化的客户关系管理&#xff08;CRM&#xff09;系统的需求日益增长。Zoho CRM&#xff0c;作为全球领先的企业级CRM解决方案提供商&#xff0c;凭借其全面的功能、高度的可定制性、以及无缝集成的生态系统&#xff0c;成…

无人机河道巡查方案,智能巡检助力水域监管革新

无人机技术的飞速发展为河道监管工作带来了创新的解决方案。无人机河道巡查以其高效、精准、智能的特点&#xff0c;正在逐步替代传统河道巡检方式&#xff0c;为水域管理提供了强有力的技术支持。 一、自主巡逻&#xff0c;提升河道监管效率 无人机河道巡查搭载先进的控制装置…

AI图书推荐:终极ChatGPT企业手册—借助Python和Java实现

《终极ChatGPT企业手册—借助Python和Java实现》&#xff08;Ultimate ChatGPT Handbook for Enterprises&#xff09;是一本关于ChatGPT的手册&#xff0c;旨在帮助企业利用AI能力、提示工程和ChatGPT的解决方案循环来改变企业景观。这本书提供了深入探讨ChatGPT的演变、能力以…

牛客NC362 字典序排列【中等 DFS Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/de49cf70277048518314fbdcaba9b42c 解题方法 DFS&#xff0c;剪枝Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回…

深入了解 CSS 预处理器 Sass

今天我们来深入探讨一下 CSS 预处理器 Sass。我们将学习什么是 Sass,如何使用它,以及它是如何工作的。 什么是 Sass? Sass 是 syntactically awesome style sheets 的缩写,是一种 CSS 预处理器。它是 CSS 的扩展,为基础 CSS 增加了更多的功能和优雅。普通的 CSS 代码很容…

BUG: VS Code C++输出中文乱码

BUG: VS Code C输出中文乱码 环境 Windows 11 VS Code 编辑器详情 在Windows 使用 cout 函数输出中文时出现乱码 问题的原因在cmd的显示编码和c程序编码的不同。cmd默认的是gbk编码&#xff0c;而VS Code 软件的CMD终端默认是utf-8编码&#xff0c;因而在输出中文文本时会出…

蓝桥杯嵌入式国赛笔记(4):多路AD采集

1、前言 蓝桥杯的国赛会遇到多路AD采集的情况&#xff0c;这时候之前的单路采集的方式就不可用了&#xff0c;下面介绍两种多路采集的方式。 以第13届国赛为例 2、方法一&#xff08;配置通道&#xff09; 2.1 使用CubeMx配置 设置IN13与IN17为Single-ended 在Parameter S…

XDebug配置几件教程,phpstorm实现http请求断点调试

写这篇的文章的初衷:网络上配置XDebug的文章有很多,XDebug也有官方的文档, PhpStorm也有官方的文档,为什么还要写那? 相信不少人,都有一种感觉,虽然教程很多,但是按教程走一遍,自己的确不能正常调试。 问题出在下面几个方面: 1. 对调试过程中,没有一定的认识,因此…

网络、HTTP、HTTPS、Session、Cookie、UDP、TCP

OSI 七层模型 应用层、表示层、会话层、传输层、网络层、数据链路层、物理层 TCP/IP 五层模型 应用层&#xff1a;为用户的应用进程提供网络通信服务&#xff08;协议&#xff1a;域名系统DNS协议&#xff0c;HTTP协议&#xff0c;SMTP协议&#xff09;传输层&#xff1a;负…