电商网站及企业微信订烟,专业做网站排名多少钱,wordpress index of,网站建设 合同IO流#xff1a;
io流中i表示input输入#xff0c;o表示output输出#xff0c;流表示数据#xff08;字符#xff0c;字节#xff0c;1个字符2个字节8个位#xff09;#xff1b;这里的输入输出是以内存为基础#xff0c;将数据从内存中输出到硬盘的过程称为输出
io流中i表示input输入o表示output输出流表示数据字符字节1个字符2个字节8个位这里的输入输出是以内存为基础将数据从内存中输出到硬盘的过程称为输出将数据从硬盘中输入到内存中称为输入这里的输入和输出就被称为io流这个数据输入输出有字符和字节所以又可分为字符流和字节流。
**字节流**一切皆为字节所有的文件都是以字节为单位存储的一个字节8个位文件的读写是以字节为单位的。无论是什么流最底层传输还是二进制数据字节流又分为字节输出流OutputStream和字节输入流InputStream。
**OutputSteam输出流**OutputSteam是所有输出流的顶级父类此类为抽象类其子类已知有 ByteArrayOutputStream往字节数组中写入数据的字节输出流、FileOutputStream往文件中写数据的字节输出流、FilterOutputStream带过滤器的字节输出流、ObjectOutputStream对象输出流、PipedOutputSream管道流
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Arrays;public class TestOutputStream {// 1.OutputSteam是一个抽象类此类定义了一些共性的方法和一些子类如FileOutputStream将内存中的数据写入到硬盘中的文件中// 2.FileOutputStream有两个构造方法分别传入一个字符串或File,表示数据写入的目的地实际就是一个路径。// 3.FileOutputStream的作用1.创建FileOutputStream对象 2.根据构造方法中的路径创建一个空文件 3.把FileOutputStream对象指向创建好的文件// 4.内存写入数据到硬盘的原理java程序--jvm虚拟机--os操作系统--os调写数据的方法--把数据写入到文件中// 5.字节输出流的使用步骤1.创建一个FileOutputStream对象构造方法中传入写入数据文件的目的地文件或路径2.调用FileOutputStream对象中的write方法将数据写入到文件 3.释放系统资源流在使用的过程中占用了一部分内存资源使用完要释放掉提高程序的效率,不释放也没关系public static void main(String[] args) throws IOException {// 1.创建一个FileOutputStream对象FileOutputStream fos new FileOutputStream(D:\\00.java高级\\练习\\javaDemo\\075.OutputStream流\\hello.txt); // 这个路径可以是相对路径这里可能会抛出异常需要处理// 2.将数据写入到文件fos.write(97); // write会抛出异常需要处理这里97表示小写的aint类型表示的是字节对应的Ascall码值97对应的字节写入到硬盘中最终是以二进制存储的任意的文本编辑器在打开文件时都会去查Ascall码表或系统码表gbk等把字节转为字符表示。fos.write(g); // 直接写入一个字节一个字节等于8个比特位10101010一个字节的比特位最大值11111111十六进制FF、十进制255fos.write(中); // 汉字在这里乱码了但是还是可以写入的// 一次写入多个字节1.支持byte数组 2.支持一部分byte数组写入(byte[] b, int off, int length)b表示byte数组off表示开始位置length表示写入数组的长度// 如果写的第一个字节是正数0-127那么显示的时候会查Ascall表如果写入的第一个字节是负数那么第一个字节会和第二个字节组成一个中文查询系统默认码表gbkbyte[] ls {97,12,99,97,12,99};fos.write(ls);byte[] ls2 {-97,-12,99};fos.write(ls2);byte[] lss {97,12,99,97,12,99};fos.write(lss,1,2);// 写入字符串利用字符串转byte数组api getBytebyte[] strls 你好.getBytes();System.out.println(Arrays.toString(strls)); // [-28, -67, -96, -27, -91, -67]fos.write(strls);// 文件中输出ag-acac燈cc浣犲ソ这里看到并没有你好是因为这里是按utf-8字符编码集三个字节为一个中文而gbk中为两个字节为一个中文// 3.释放资源fos.close();// 4.追加数据每次执行上面的代码实际都是将源文件覆盖掉的如果想要在当前文件继续追加数据可以使用两个参数的构造方法FileOutputStream其中第一个构造方法参数表示目标文件第二个参数表示是否开启追加FileOutputStream fos2 new FileOutputStream(D:\\00.java高级\\练习\\javaDemo\\075.OutputStream流\\append.txt, true);fos2.write(g);// 每次执行都会追加字符上去fos2.write(\r\n.getBytes()); // 换行win(\r\n)、linux(/n)、mac(/r)fos2.write(你好.getBytes());fos2.close();};
}
InputStream字节输入流: 此类也是io流类的一个子类它也是抽象的并且是所有字节输入流的父类它下面还有一些子类BufferedInputStream、AudioInputStream读取音频、ByteArrayInputStream读取字节数组、FileInputStream读取文件、DataInputStream、FilterInputStream带过滤器的、read()、OutputStream、PushbackInputStream、ObjectInputStream读取对象的、PipedInputStream管道流、SequenceInputStream处理队列的、StringBufferInputStream读取字符串缓存区
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;public class TestFileInputStream {public static void main(String[] args) throws IOException {// 1.FileInputStream文件字节流输入流将硬盘中文件中的数据读取到内存中其构造方法中参数表示要读取文件的路径或文件// 2.构造方法的作用1.创建一个FileInputStream对象 2.将FileInputStream对象指定构造方法中要读取的文件// 3.读取数据原理java程序--jvm--os--os读取数据的方法--读取文件// 4.字节输入流的使用步骤1.创建一个FileInputStream对象,构造方法参数指明文件 2.调用FileInputStream的read方法读取文件 3.调用FileInputStream的close方法释放资源// 1.创建FileInputStream对象FileInputStream fis new FileInputStream(D:\\00.java高级\\练习\\javaDemo\\076.InputStream流\\test.txt);int num;do {num fis.read(); // 2.读取文件中的一个字节并返回读取到文件末尾返回-1System.out.println(num);System.out.println((char)num);byte[] ls new byte[2];int num2 fis.read(ls); // read传入一个字节数组时读取字节数组长度的字节并返回给字节数组System.out.println(Arrays.toString(ls)); // [0, 0]System.out.println(num2);System.out.println((char)num2);System.out.println(---------------);} while (num ! -1);// 3.释放资源fis.close();};
}
文件复制demo:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class CopyFileDemo {public static void main(String[] args) throws IOException {// 创建读文件的流将内存中的数据流输出读取,写入到文件中FileOutputStream fos new FileOutputStream(D:\\00.java高级\\练习\\javaDemo\\076.InputStream流\\copy_test.mp4);// 创建写文件的流将文件读取到内存缓存区FileInputStream fis new FileInputStream(D:\\00.java高级\\练习\\javaDemo\\076.InputStream流\\test.mp4);// 一读一写实现文件拷贝int bts 0; // 记录每次读取有效字节个数// 循环将硬盘中的文件数据写入内存,如果不指定字节数量每次都会读取一个字节写入一个字节这样速度很慢可以读取多个字节写入多个字节byte[] size new byte[1024 * 50]; // 值越大速度越快// while((bts fis.read()) ! -1) {while((bts fis.read(size)) ! -1) { // 优化读取多个字节// 将内存中的流输出到新的文件中// fos.write(bts);fos.write(size,0,bts); // 优化写入多个字节};//释放资源fos.close();fis.close();};
}
**字符流**字节流读取中文时可能会有显示不全乱码的问题因为中文占有多个字节存储为解决这个问题java提供了字符流类以字符为单位读写数据专门用于处理文本文件的Reader类此类为字符输入流最顶层的类此类也是一个抽象类其子类有BufferedReader缓存流、CharArrayReader字符数组流、FilterReader过滤流、InputStreamReader转换流、PipedReader管道流、StringReader读取字符串流
一个中文如果是GBK编码则占用2个字节如果是utf-8编码则占用3个字节。
**字符输入流**将硬盘文件中的数据以字符的方式读取到内存中
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;public class TestReader {// 1.Reader字符输入流是字符输入流的最顶层父类定义了一些共性的成员方法是一个抽象类// 2.共性方法read()读取单个字符并返回、read(char[] cbuf)一次读取多个字符将字符读取到数组// 3.close()关闭该流并释放与之关联的所有资源// 4.fileReader继承于InputStreamReader,InputStreamReader又继承于Reader,fileReader文件字符输入流把硬盘文件中数据以字符的方式读取到内存中// 5.构造参数FileReader()里面可以传入一个文件路径或一个文件实例// 6.fileReader构造方法的作用1.创建一个FileReader对象 2.把FileReader对象指向要读取的文件// 7.字符输入流的使用步骤1.创建FileReader对象构造方法中绑定要读取的数据源 2.使用FileReader对象中的read方法读取文件 3.释放资源public static void main(String[] args) throws IOException {// 1.创建FileReader对象FileReader fs new FileReader(D:\\00.java高级\\练习\\javaDemo\\077.Reader字符流\\test.txt);// 2.使用reader读取字符// 读取单个字符//int ln 0; // 读取字符的长度//while((ln fs.read()) ! -1){// System.out.println(ln);//};// 读取多个字符int ln2 0;char[] ls new char[1024 * 50];while((ln2 fs.read(ls)) ! -1){System.out.println(new String(ls,0,ln2));};// 3.释放资源fs.close();};
}
字符输出流 writer类是io类的一个子类是所有字符输出流的最顶层父类是一个抽象类其子类有BufferedWriter、CharArrayWriter、FilterWriter、OutputStreamWriter、PipedWriter、PrintWriter、StringWriter
import java.io.FileWriter;
import java.io.IOException;public class TestFileWriter {// 1.FileWriter: 把内存中的字符数据写入到文件中// 2.构造方法FileWriter其中可以传递一个文件路径或者文件实例其作用1.创建一个FileWriter对象 2.根据构造方法中的文件或文件路径创建文件 3.把FileWriter对象指向创建好的文件// 3.使用步骤1.创建FileWriter对象构造方法中绑定要写入数据的目的地 2.使用write方法将数据写入到内冲缓存区中字符转字节的过程3.使用flush将内存缓存区中的数据刷新到文件中 4.释放资源会把内存缓存区中的数据刷新到文件中public static void main(String[] args) throws IOException {// 1.创建FileWriter对象FileWriter fw new FileWriter(D:\\00.java高级\\练习\\javaDemo\\078.Writer字符输出流\\hello.txt, false); // 第二个参数表示是否开启续写开启后每次执行文件都会进行追加写入否则会创建新文件覆盖原文件// 2.使用FileWriter中的write把数据写入到内存缓冲区字符转换为字节流的过程fw.write(97); // 此时并没有将数据直接写入到文件中而是写入内存缓冲区// write可直接传递一个字符数组进行写入char[] list {a,b,c};fw.write(list);// write可直接写入字符串或字符串一部分fw.write(hello123);fw.write(今天又是摸鱼的一天, 2, 3);// 换行写win:\r\n linux:/n mac:/rfw.write(\r\n);// write可以指定字符数组某一个部分写入fw.write(list,1,2);// 3.使用FileWriter中的flush方法把内存缓冲区中的数据刷新到文件中fw.flush(); // 如果调用了close方法会自动刷新数据到文件中fw.close();};// 4.flush方法和close方法的区别flush刷新缓冲区流对象可以继续使用close先刷新缓冲区然后通知系统释放资源流对象不可以再使用了
}属性集Properties
可以创建一个键值对的集合并搭配流可以将数据存储到文件或从文件中将数据读取到集合中。
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;public class PropertiesTest {// 1.Properties继承于Hashtable,该类表示了一个持久的属性集该属性可保存在流中或从流中加载Properties是一个唯一和io流相结合的集合// 2.可以使用Properties集合中的方法store,把集合中的临时数据持久化的写入到硬盘中可以使用load方法将文件中键值对读取到集合中// 3.属性列表中每个键及其对应值都是一个字符串Properties集合是一个双链集合key和value默认都是字符串// 4.Properties集合有两个常用方法setProperty(String key, String value)类似调用Hashtable的put进行存储值、通过getProperty(String key)通过key找到value类似Map中的get方法还有一个遍历属性key的方法stringPropertyNames,它返回此属性列表中的键集其中该键及其对应值是字符串此方法相当于Map集合中的keySet方法public static void main(String[] args) throws IOException {// 1.创建一个Properties集合Properties ps new Properties();// 2.往集合中添加属性及值ps.setProperty(name, 小迪);ps.setProperty(age, 18);// ps.put(12,12); // 支持put方法但是不推荐// 3.遍历集合SetString set ps.stringPropertyNames();for (String key: set) {// 拿到keySystem.out.println(key);// 拿到值System.out.println(ps.getProperty(key));};// 4.store方法将数据写入到硬盘中传递的如果是字节流那么就不能写入中文如果传递的是字符流才可以写中文进去store还可以传入注释注释不能使用中文不然会乱码用来说明保存文件是做什么用的// 创建字节或字符输出流对象FileWriter fw new FileWriter(D:\\00.java高级\\练习\\javaDemo\\079.PropertiesTest\\test.txt);// 将Properties集合中的数据存储到文件中ps.store(fw,save data test); // store可以把数据持久化到硬盘中第一个参数为流对象参数二为说明; 数据以keyvalue的形式保存在了文件中// 释放资源fw.close();// 6.load方法可以将文件中的键值对读取到集合中:参数如果传递了字节输入流那么就不能读取中文键值对如果传递了字符输入流就可以读取中文// 使用步骤1.创建Properties集合对象 2.调用集合对象的方法load将文件中的值读取到集合中 3.遍历集合对象查看值// 注意事项存储数据的文件中键与值之间可以使用或其它符合连接、存储键值对的文件中可以#开头为注释注释不会被读取到集合中、键和值默认就是字符串形式无需再加引号Properties ps2 new Properties();ps2.load(new FileReader(D:\\00.java高级\\练习\\javaDemo\\079.PropertiesTest\\test.txt));SetString lskey ps2.stringPropertyNames();for (String key: lskey) {System.out.println(key --- ps.getProperty(key));};};}缓冲流
缓冲流能够转换编码能持久化存储对象的序列化流等缓冲流都是在基础的流上面创建而来的是将多个基本流存到数组中之后一次进行处理。 缓冲流也叫高效流是对4个基本的FileXXX流的增强它们分别为
字节缓冲流BufferedInputStream、BufferedOutputStream
字符缓冲流 BufferedReader、BufferedWriter
前面的基本流在读写的时候都是非常慢的缓冲流相对于基本流快很多。
字节缓冲输出流和字节缓冲输入流
import java.io.*;public class BufferedOutInputStreamTest {// 字节缓冲输出流部分// 1.BufferedOutputStream基础于OutputStream,构造方法BufferedOutputStream(),里面可以传递OutputStream来创建一个缓冲流输出流以将数据写入到指定的底层输出流另一种方式是在第一个基础上面在传递第二个参数指定缓冲区大小// 2.使用步骤1.创建FileOutputStream对象构造方法中指定要输出的目的地 2.创建BufferedOutputStream对象构造方法中传递FileOutputStream对象提高FileOutputStream对象效率 3.使用BufferedOutputStream对象中的write将数据写入到指定的缓冲区中 4.使用flush把内部缓冲区中的数据刷新到文件中 5.close释放资源public static void main(String[] args) throws IOException {// 1.创建基本的输出流构造方法中指定要输出的目的地FileOutputStream fi new FileOutputStream(D:\\00.java高级\\练习\\javaDemo\\080.缓冲流\\test.txt);// 2.创建一个缓冲流对象里面传递基本输出流对象BufferedOutputStream bos new BufferedOutputStream(fi);// 3.调用缓冲流对象的write写数据write中传递字节数组bos.write(一些数据被写入到内部缓冲区中.getBytes()); // 此时只是创建了文件但是数据是还没有刷新到文件里面// 4.刷新数据到文件中bos.flush();// 5.释放资源bos.close();// 字节缓冲输入流部分// 1.BufferedInputStream继承于InputStream构造方法可以传递一个参数输入流也可以指定第二个参数指定缓冲区大小// 2.使用步骤哦1.使用FileInputStream创建一个基本字节输入流构造方法中绑定要读取的数据源 2.使用BufferedInputStream创建对象构造方法中传递FileInputStream对象提高FileInputStream对象的读取效率// 3.使用BufferedInputStream对象中的read方法读取文件// 4.释放资源// 1.创建基本输入流绑定要输入的文件源FileInputStream fis new FileInputStream(D:\\00.java高级\\练习\\javaDemo\\080.缓冲流\\test.txt);// 2.创建BufferedInputStream对象构造方法中传递基本流对象BufferedInputStream bis new BufferedInputStream(fis);// 3.使用read方法读取文件int ln 0;//while((ln bis.read()) ! -1){// System.out.println(ln);//};// 优化为每次读取一部分字节byte[] list new byte[1024 * 50];while((ln bis.read(list)) ! -1){System.out.println(new String(list,0,ln));};// 释放资源bis.close();};
}字符缓冲输出流和字符缓冲输入流
import java.io.*;public class BufferedWriterDemo {public static void main(String[] args) throws IOException {// 字符缓冲输出流部分// 1.BufferedWriter继承于Writer类它为字符缓冲流// 2.构造方法BufferedWriter里面可以传递一个默认大小的输出缓冲字符输出流也可以接收第二个参数来指定大小输出缓冲区提高FileWriter的写入效率// 3.BufferedWriter特有方法newLine()写入一个分隔符会根据不同的操作系统获取不同的航分割符// 4.使用步骤// 1.创建字符缓冲输出流对象构造方法中传递字符输出流// 2.调用字符缓冲输出流的方法write,把数据写入到内存缓冲区中// 3.调用字符缓冲输出流中的flush方法将数据刷新到文件中// 4.释放资源// 1.创建BufferedWriter对象里面接收一个FileWriter实例BufferedWriter bw new BufferedWriter(new FileWriter(D:\\00.java高级\\练习\\javaDemo\\080.缓冲流\\test2.txt, true));// 2.往文件中写入内容循环写入数据并测试newLine方法进行换行for (int i 0; i 5; i){bw.write(写入字符串i);bw.newLine();};// 3.刷新数据到文件中bw.flush();// 4.释放资源bw.close();// 字符缓冲输入流部分// 1.BufferedReader继承于Reader方法// 2.构造方法BufferedReader用于创建一个使用默认大小输入缓冲区的缓冲字符输入流可以接收第二个参数来指定缓冲区的大小// 3.使用步骤 1.创建字符缓冲输入流对象构造方法中传递字符输入流 2.使用字符缓冲区输入流对象的read或readLine读取文本 3.释放资源// 1.创建字符缓冲输入流对象BufferedReader br new BufferedReader(new FileReader(D:\\00.java高级\\练习\\javaDemo\\080.缓冲流\\test3.txt));// 2.读取文本//int st br.read(); // read只能读取单个字符的值使用readLine可以读取每行字符串//System.out.println(st);String sl br.readLine(); // readLine每次只能读取一行内容如果没有内容过来就会返回nullSystem.out.println(sl);String newStr;while((newStr br.readLine()) ! null){System.out.println(newStr);};// 3.释放资源br.close();};
}转换流
字符编码
按照某种规则将字符储存到计算机中称为编码反之将计算机中的二进制数按照某种规则解析显示出来称为解码字符编码就是一套自然语言的字符与二进制之间的对应规则编码表生活中文字和计算机二进制的对应规则
字符集 字符集也叫编码表是一个系统支持所有字符的集合包括各国加文字、标点符号、图形符号、数字等常见的字符集有Ascall字符集、GBK字符集、Unicode字符集。
当一个文件使用的编码和读取文件使用的编码不一致时此时读取到就会发生乱码为解决乱码问题可以使用转换流。
InputStreamReader和OutputStreamWriter是转换流的桥梁:
OutputStreamWriter是字符流通向字节流的桥梁可以指定字符编码将要写入的字符编码成字节就是将能看懂的转换为看不懂的是编码的过程。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;public class OutputStreamWriterDemo {// 1.OutputStreamWriter的构造方法第一个参数是一个文件输出流也可以传递第二个参数用来指定字符编码将字符编码后以字节的形式存储在文件// 2.使用步骤1.创建OutputStreamWriter对象构造方法中传递字节输出流和指定编码表名称 2.调用write方法将字符转换为字节存储到缓冲区中进行编码3.调用flush方法把缓冲区中的字节刷新到文件中 4.释放资源public static void main(String[] args) throws IOException {// 1.创建一个OutputStreamWriter对象OutputStreamWriter osw new OutputStreamWriter(new FileOutputStream(D:\\00.java高级\\练习\\javaDemo\\081.OutputStreamWriter\\test.txt),gbk); // 第二个参数指定编码格式后将以此编码格式对文件编码存储// 2.写数据osw.write(你好123);// 3.刷新文件osw.flush();// 4.释放资源osw.close();};
}
InputStreamReader将字符文件读取出来以可以指定编码格式进行解码不懂的字符到可以看懂的字节的过程。
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;public class InputStreamReaderDemo {// 1.InputStreamReader传递第一个参数为字节输入流也可以传递第二个参数指定编码集// 2.使用步骤1.创建InputStreamReader对象构造方法中传递字节输入流和指定的编码名称这里编码格式要和文件的一致否则会乱码 2.使用InputStreamReader的read方法读取文件 3.释放资源public static void main(String[] args) throws IOException {// 1.创建InputStreamReader对象InputStreamReader isr new InputStreamReader(new FileInputStream(D:\\00.java高级\\练习\\javaDemo\\081.OutputStreamWriter\\test.txt), gbk); // 文件是gbk,读取的时候也要用gbk否则会乱码// 2.读取文件int ln 0;while((ln isr.read()) ! -1){System.out.println((char)ln);};// 3.释放资源isr.close();};
}
序列化和反序列化
对象序列化流将对象以字节流的方式存储
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;public class ObjectOutputStreamTest {// 对象序列化// 1.ObjectOutputStream继承于OutputStream其作用是将对象以流的方式写入到文件中保存// 2.构造方法构造方法接收一个字节输出流// 3.特有方法writeObject(Object obj),将对象写入到ObjectOutputStream,需要特别注意这里传入的对象需要实现序列化和反序列化接口Serializable,只需要实现做标记其它不用做否则会抛异常// 4.使用步骤1.创建ObjectOutputStream对象构造方法中传递字节输出流 2.使用其方法writeObject方法把对象写入到文件中 3.释放资源public static void main(String[] args) throws IOException {// 1.创建ObjectOutputStream对象构造方法中传递输出流ObjectOutputStream ojos new ObjectOutputStream(new FileOutputStream(D:\\00.java高级\\练习\\javaDemo\\082.对象序列化\\test.txt));// 2.使用writeObject写入一个对象ojos.writeObject(new Person(韩梅梅, 25)); // 这里是以字节的方式存储的直接打开查看是乱码的// 3.释放资源ojos.close();};
}对象的反序列化流把文件中储存的对象以流的方式读取出来。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;public class ObjectInputStreamTest {// 1.ObjectInputStream继承于InputStream,其作用是对象的反序列化,把文件中储存的对象以流的方式读取出来// 2.构造方法接收一个指定的InputStream字节输入流// 3.使用步骤1.创建objectInputStream对象构造方法中传递字节输入流 2.使用其特有方法readObject读取对象文件 3.释放资源 4.使用读取出来的对象打印public static void main(String[] args) throws IOException, ClassNotFoundException {// 1.创建ObjectInputStream对象里面传递文件输入流ObjectInputStream ojis new ObjectInputStream(new FileInputStream(D:\\00.java高级\\练习\\javaDemo\\082.对象序列化\\test.txt));// 2.使用其特有方法readObject读取文件流Object ob ojis.readObject();// 3.释放资源ojis.close();// 4.查看读取到的对象System.out.println(ob);// ob是Object类型将转Person类型Person p (Person)ob;System.out.println(p.getNames()); // 韩梅梅};
}
提示静态属性是不能被序列化的即使序列化了它的值还是默认的值在创建对象时传递的值并不会赋值成功除了static修饰的静态属性外还有一个关键字transient关键字修饰的成员变量也是不能被序列化的此时如果不想成员变量被序列化可以使用此关键字但它却没有静态的含义。
在序列化和反序列化对象时在对象文件中加入private static final long serialVersionUID 一个值;可以有效防止序列化冲突报错的问题
打印流
PrintStream为打印流其特点只负责数据的输出不负责数据的读取永远不会抛出IOException
import java.io.FileNotFoundException;
import java.io.PrintStream;public class PrintStreamDemo {// 1.PrintStream为打印流继承于OutputStream为其它输出流添加了功能使它们能够方便地打印各种数据值表示形式// 2.特有方法print和println// 3.构造方法参数可以是指定输出的目的地是一个文件或字节输出流或一个文件路径public static void main(String[] args) throws FileNotFoundException {// 1.创建一个打印流对象PrintStream ps new PrintStream(D:\\00.java高级\\练习\\javaDemo\\083.printStream打印流\\error.txt);// 2.写入打印信息ps.write(a);ps.write(98);ps.println(你好哈); // println或print打印任意数据类型且不会自动转换为字节如打印97并不会显示a而write是会自动转换为字节的而且不支持字符串打印// 3.System.setOut(打印流对象);可以将以下print的东西打印到输出文件中特别提醒setOut方法前面的不会不打印到文件中而是继续在控制台打印System.setOut(ps);System.out.println(123sdfs);// 4.释放资源ps.close();};
}网络编程
软件结构
c/s结构全称client/server结构指客户端和服务器结构常见程序有qq、网盘等。
b/s结构全称browser/server结构指浏览器和服务器结构常见浏览器有谷歌、火狐等都是通过网址去访问。
两种架构都需要网络网络编程就是在一定的协议下实现两台计算机的通信的程序。
网络通信协议 通过计算机网络可以实现多台计算机的连接位于同一网络中的计算机在进行连接和通信的时候需要遵循一定的规则这些规则被称为网络协议它对数据的传输格式、传输速率、传输步骤等做了统一规定通信双方必须同时遵循协议才能完成数据交换。
TCP/ip协议 也叫传输控制协议/英特网互联协议Transmission Control Protocol/Internet Protocol是因特网最基础应用最广泛的协议它内部包含一系列用于处理数据通信的协议采用了4层的分层模型每一层都呼叫它的下一层所提供的协议来完成自己的需求。 协议分类 通信的协议还是比较复杂的java.net包中包含的类和接口它们提供了低层次的通信细节我们可以直接使用这些类和接口来专注于网络程序的开发而不用考虑通信的细节。java.net包中提供了两种常见的网络协议的支持
UDP: 用户数据报协议User Datagram ProtocolUDP是无连接通信协议数据的发送端和接收端无需建立逻辑连接简单的说当一台计算机向另一台计算机发送数据时发送端不会确认接收端是否存在就会发出数据同样接收端在接收数据时也不会向发送端反馈是否收到数据其特点耗资小、通信效率高常用语音频和视频及普通数据的传输例如视频会议都使用UDP协议因为这种情况即使偶尔丢失一两个包也不会对接收结果产生太大影响弊端一次发送的数据不能超过64kb,超出这个范围就不能发送了。
TCP:传输控制协议Transmission Control Protocol是面向连接的通信协议即传数据之前在发送端和接收端建立逻辑连接然后再传输数据其特点两台计算机之间可无差错的进行数据传输保证数据传输的安全应用十分广泛如文件下载浏览网页等。客户端和服务端每次连接都是由客户端发出连接请求每次连接的创建都需要3次握手3次握手完后才进行数据交换 网络编程三要素
协议计算机网络通信必须遵循网络规则
ip地址指互联网协议地址lnternet Protocol Address俗称ip,计算机设备的唯一编号ip可分IPv4和IPv6, IPv4是一个32位的二进制数通常被分为4个字节表示成a.b.c.d Ipv6是为了扩大地址空间采用128位地址长度每16个字节一组分成8组十六进制数表示成ABCD: EFe1: 2345: 6789: ABCD: EF01: 2345: 6789,这样就解决了网络地址资源数量不够用的问题。
查看本地网络配置命令终端输入ipconfig
端口端口是计算机对每一个程序的编号端口号有2个字节组成取值范围在0~65535这个编号并非和某个程序绑定死而是可以指定的。如后端启动某个服务端指定端口号是3000那么前端通过ip加3000这个端口就可以找到这个服务。
TCP通信程序
TCP通信能实现两台计算机之间数据交互通信的两端要严格区分为客户端与服务端。
两端通信时步骤1.服务端程序需要先启动等待客户端的连接。2.客户端主动连接服务器端连接成功才能通信服务器不可以主动连接客户端。
在java中提供了两个类用于实现TCP通信程序
1.客户端java.net.Socket类用户创建客户端Socket对象向服务端发出连接请求服务端响应请求两者建立连接开始通信。
2.服务端java.net.ServerSocket类用于创建服务端对象相当于开启一个服务等待客户端的连接。
服务器端代码
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class TcpServer {// TCP通信服务端接收客户端的请求读取客户端发送的数据给客户端回写数据需要使用ServerSocket类此类实现服务器套接字// 1.构造方法ServerSocket(int port)此类创建特定端口的服务器套接字// 2.服务器必需明确是哪个客户端请求的服务器所以可以使用accept方法获取到请求的客户端对象Socket// 3.使用步骤1.创建服务器ServerSocket对象和系统要指定的端口号 2.使用ServerSocket对象的accept方法获取客户端Socket对象 3.使用Socket对象中的方法getInputStream获取InputStream对象 4.使用网络字节输入流InputStream对象的read方法读取客户端发送的数据 5.使用Socket对象中的方法getOutputStream获取网络字节输出流OutputStream对象 6.使用网络字节输出流OutputStream对象中的write方法给客户端写数据 7.释放资源Socket,ServerSocketpublic static void main(String[] args) throws IOException {// 1.创建服务器端ServerSocket对象并指定端口ServerSocket servers new ServerSocket(3000);// 2.获取请求服务器端的客户端Socket对象Socket client servers.accept();// 3.使用Socket对象中的getInputStream方法获取网络字节输入流InputStream对象InputStream iso client.getInputStream();// 4.使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据byte[] bts new byte[1024];int ln iso.read(bts);String msg new String(bts,0,ln);System.out.println(服务器接收到数据 msg);// 5.使用Socket对象中的getOutputStream方法获取网络字节输出流OutputStream对象OutputStream ois client.getOutputStream();// 6.服务器回复客户端ois.write(你好客户端,我是服务器A.getBytes());// 7.释放流client.close();servers.close();};
}客户端代码
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;public class TcpClient {// TCP客户端实现客户端实现使用Socket类此类实现客户端套接字套接字是两台机器间通信的端点套接字包含了ip和端口的网络单位// 1.构造方法Socket(String host, int port),参数一 为服务器的ip或主机名参数二为端口号// 2.成员方法1.OutputStream getOutputStream()返回此套接字的输出流 2.InputStream getInputStream()返回此套接字的输入流 3.close()关闭此套接字// 3.实现步骤1.创建一个客户端实例对象Socket,构造方法中传递ip和端口 2.使用Socket对象中的getOutputStream()方法获取网络字节输出流OutputStream对象 3.使用网络字节输出流OutputStream对象中的write方法给服务器发送数据 4.使用Socket对象中的getInputStream方法获取网络字节输入流InputStream对象 5.使用网络字节输入流InputStream对象中的read方法读取服务器回显的数据 6.释放资源Socket// 4.提示1.客户端和服务端进行交互时必须使用Socket提供的网络流不能使用自己创建的流对象 2.当我们创建客户端Socket对象时此时就会去请求服务端和服务器经过3次握手建立连接这时服务器如果没有启动就会抛出异常如果服务器启动那么就可以正常进行交互。public static void main(String[] args) throws IOException {// 1.创建Socket客户端对象里面传递ip和端口号Socket client new Socket(127.0.0.1, 3000);// 2.使用Socket实例对象的getOutputStream得到一个字节输出流OutputStream ots client.getOutputStream();// 3.调用输出流的write方法向服务器写数据ots.write(你好服务器我是客户端001.getBytes());// 4.使用Socket对象中的getInputStream方法获取网络字节输入流InputStream对象InputStream iso client.getInputStream();// 5.使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据byte[] bts new byte[1024];int ln iso.read(bts);String msg new String(bts,0,ln);System.out.println(客户端接收到数据 msg);// 6.释放资源client.close();};
}文件上传案例图片
服务端代码
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;public class TcpServer {// 服务端实现步骤public static void main(String[] args) throws IOException {// 1.创建服务器ServerSocket对象指定端口和ip:ServerSocket server new ServerSocket(3000);// 优化循环一直监听是否有客户端访问有访问就执行起监听作用while(true){// 2.使用ServerSocket中的accept方法获取客户端Socket对象Socket client server.accept();// 优化当有多个客户端上传文件时使用多线程new Thread(new Runnable(){Overridepublic void run() {try {// 3.使用Socket中的getInputStream获取网络字节输入流InputStream对象InputStream inStream client.getInputStream();// 4.判断服务器中是否有需要存储文件的文件夹如果没有需要创建文件夹File files new File(D:\\00.java高级\\练习\\javaDemo\\085.tcp实现文件上传\\uploads);if (!files.exists()) {files.mkdir();}// 5.创建一个本地字节输出流FileOutputStream对象构造方法中绑定要存储文件的目的地String strTemp \\files System.currentTimeMillis() new Random(999999999).nextInt() .png;FileOutputStream outStream new FileOutputStream(files strTemp);// 6.使用网络字节输入流InputStream对象中的read读取客户端上传的文件int len 0;byte[] bytes new byte[1024 * 1];while((len inStream.read(bytes)) ! -1){// 7.使用本地字节输出流FileOutputStream对象中的write将文件写入到服务器硬盘中outStream.write(bytes,0,len);};// 8.使用Socket对象中的getOutputStream获取到网络字节输出流OutputStream对象OutputStream outStreamToClient client.getOutputStream();// 9.使用Socket获取的OutputStream对象回写数据给客户端outStreamToClient.write(文件上传成功!.getBytes());// 10.释放资源outStream.close();client.close();} catch (IOException e) {System.out.println(异常 e);}}}).start();}// 服务器一直处于监听客户端进来这里也没必要关闭
// server.close();};
}客户端代码
import java.io.*;
import java.net.Socket;public class TcpClient {// 客户端实现步骤// 1.创建一个本地字节输入流FileInputStream对象构造方法中绑定要读取的数据源// 2.创建一个客户端Socket对象构造方法中绑定服务器ip地址和端口号// 3.使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象// 4.使用本地字节输入流FileInputStream对象中的read读取本地文件// 5.使用网络字节输出流OutputStream对象中的write,把读取到的文件上传到服务器// 6.使用Socket中的方法getInputStream获取网络字节输入流InputStream对象// 7.使用网络字节输入流中InputStream对象的read读取服务器回写的数据// 8.释放资源FileInputStream,Socketpublic static void main(String[] args) throws IOException {// 1.创建一个本地字节输入流FileInputStream对象构造方法中绑定要读取的数据源FileInputStream pickFile new FileInputStream(D:\\00.java高级\\练习\\javaDemo\\085.tcp实现文件上传\\test.png);// 2.创建一个客户端Socket对象构造方法中绑定服务器ip地址和端口号Socket client new Socket(127.0.0.1,3000);// 3.使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象OutputStream outStream client.getOutputStream();// 4.使用本地字节输入流FileInputStream对象中的read读取本地文件int len 0;byte[] bytes new byte[1024 * 1];while((len pickFile.read(bytes)) ! -1){// 5.使用网络字节输出流OutputStream对象中的write,把读取到的文件上传到服务器outStream.write(bytes, 0, len);};// 为防止服务器和客户端相互等待进入卡死状态这里文件上传完后客户端终止继续写入数据client.shutdownOutput();// 6.使用Socket中的方法getInputStream获取网络字节输入流InputStream对象InputStream inStream client.getInputStream();while((len inStream.read(bytes)) ! -1){// 7.使用网络字节输入流中InputStream对象的read读取服务器回写的数据,然后打印System.out.println(new String(bytes,0,len));};// 8.释放资源FileInputStream,SocketpickFile.close();client.close();};
}B/S服务案例
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class WebServer {public static void main(String[] args) throws IOException {// 1.创建一个SocketServer对象并指定一个端口ServerSocket server new ServerSocket(3000);while(true){new Thread(new Runnable(){Overridepublic void run(){// 2.使用SocketServer对象的accept方法获取客户端请求对象try {Socket client server.accept();// 3.使用Socket中的getInputStream方法获取Socket对象中的InputStream对象InputStream inStream client.getInputStream();// 3.使用InputStream对象中的read方法读取客户端请求信息//byte[] bytes new byte[1024];//int len 0;//while((len inStream.read(bytes)) ! -1){// System.out.println(new String(bytes,0,len));// // 浏览器输入localhost:3000后这里打印信息// // GET / HTTP/1.1 // 注意 这里实际是可以拿到访问路径的如果在浏览器输入http://localhost:3000/webhtml/index.html,可以看到打印信息GET /webhtml/index.html HTTP/1.1, 不难看出GET后第一个斜杠开始到空格即是访问路径// // Host: localhost:3000// // Connection: keep-alive// // sec-ch-ua: Google Chrome;v107, Chromium;v107, NotA?Brand;v24// // sec-ch-ua-mobile: ?0// // sec-ch-ua-platform: Windows// // Upgrade-Insecure-Requests: 1// // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36// // Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/avif,image/webp,image/apng,*/*;q0.8,application/signed-exchange;vb3;q0.9// // Sec-Fetch-Site: none// // Sec-Fetch-Mode: navigate// // Sec-Fetch-User: ?1// // Sec-Fetch-Dest: document// // Accept-Encoding: gzip, deflate, br// // Accept-Language: en,zh-CN;q0.9,zh;q0.8//};// 优化改造从请求打印可以看出我们只有第一行内容暂时对于我们有效我们可以只读第一行内容因此上面部分注释看下面// 将InputStream字节输入流转换为字符缓冲输入流BufferedReader binStream new BufferedReader(new InputStreamReader(inStream));// 使用readLine读取一行String url binStream.readLine();System.out.println(url); // GET /webhtml/index.html HTTP/1.1 可以看到第一行请求路径已经拿到了此时我们继续处理拿到对我们有用的部分/webhtml/index.htmlString[] urlList url.split( ); // 使用split以空格进行切割得到一个字符串数组拿到索引为1的字符串System.out.println(urlList[1]); // /webhtml/index.html , 去掉字符串前面的第一个斜杠String webUrl urlList[1].substring(1); // 使用substring从1位置开始截取字符串System.out.println(webUrl); // webhtml/index.html// 4.创建本地字节输入流构造方法中绑定html文件路径FileInputStream finStrem new FileInputStream(webUrl);// 5.使用Socket对象中的getOutputStream方法获取OutputStream网络字节输出流OutputStream outStream client.getOutputStream();// 6.使用OutputStream中的write方法写数据给客户端// 写入固定给浏览器识别的信息outStream.write(HTTP/1.1 200 0K\r\n.getBytes());outStream.write(Content-Type:text/html\r\n.getBytes());outStream.write(\r\n.getBytes());// 读取html文件并回写给客户端因为这里文件可能太大一般都是循环读完为止byte[] bytes new byte[1024];int len 0;while((len finStrem.read(bytes)) ! -1){outStream.write(bytes,0,len);};// 7.释放资源finStrem.close();client.close();} catch (IOException e) {throw new RuntimeException(e);}};}).start();// server.close(); // 一直监听所以不用关闭}// 提示 这里考虑到多个客户访问及web项目中自发请求的问题这里做了循环监听及多线程处理只需要将Socke获取客服端部分及读取文件以及回写放到多线程中并以循环的方式不断监听即可};
}提示本文图片等素材来源于网络若有侵权请发邮件至邮箱810665436qq.com联系笔者删除。 笔者苦海