9.IO
流 : 数据(字符、字节) 1字符=2字节
顶层父类
输入流(读入内存) | 输出流(写入硬盘) | |
---|---|---|
字节流 | InputStream | OutputStream |
字符流 | Reader | Writer |
一切均为字节,则字节流可以读取任意文件。
9.1字节输出流OutputStream
public abstract class OutputStream extends Object implements Closeable, Flushable{
void close(); //关闭此输出流并释放与此流有关的所有系统资源
void flush(); //刷新此输出流并强制写出所有换成缓冲的输出字节
void write(byte[] b); //将b.length 个字节从制定的byte数组写入此输出流
void write(byte[] b,int off, int len); //将指定byte数组中从偏移量off开始的len个字节写入此输出流
abstract void write(int b); //将指定的字节写入此输出流
}//write方法将数据从内存写到硬盘中
直接已知的子类:ByteArrayOutputStream
, FileOutoutStream
, FilterOutputStream
, ObjectOutputStream
, PipedOutputStream
学习重点 :FileOutputStream
构造方法:
FileOutputStream(String name )创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(File file)创建一个向指定File 对象表示的文件中写入数据的文件输出流。
参数:写入数据的目的,
String name :目的地是一个文件的路径
File file:目的地是- -个文件
构造方法的作用:
1.创建一个FileOutputStream对象
2.会根据构造方法中传递的文件/文件路径,创建一个空的文件
3.会把FileOutputStream对象指向创建好的文件|
写入数据的原理:java程序–》JVM–》OS——》OS调用写数据的方法。写入到文件中
- 创建FileOutputStream对象, 构造方法写传入数据的目的地
- 调用方法write,把数据写入到文件中。
- 释放资源,情况内存。
9.1.1写入数据或多个字节
public class Demo01OutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("D:\\IDEA\\Projects\\a.txt");
fos.write(97);
fos.close();
}
}
//一次性写多个字节,使用String类的方法getBytes() 把字符串转化为字节数组
public class Demo01OutputStream {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("D:\\IDEA\\Projects\\b.txt");
//byte[] bytes1 = {65,66,67};
byte[] bytes2 = "你好".getBytes();
System.out.println(Arrays.toString(bytes2)); //[-28, -67, -96, -27, -91, -67] 运行结果,因为是utf-8,中文为3字节
fos.write(bytes2);
fos.close();
}
}
9.1.2数据追加写和换行写
追加写/续写:使用两个参数的构造方法
FileOutputStream(String name, boolean append)创建一个向具有指定name的文件中写入数据的输出文件流。
FileOutputStream(File file, boolean append) 创建一个向指定File对象表示的文件中写入数据的文件输出流。
参数:
String name, File file:写入数据的目的地
boolean append :追加写开关
true :创建对象不会覆盖源文件,继续在文件的末尾追加写数据
false:创建一个新文件, 覆盖源文件
写换行:写换行符号
windows: \r\n
Linux: /n
mac: /r
9.2字节输入流InputStream
java. io. InputStream:字节输入流 此抽象类是表示字节输入流的所有类的超类。
定义了所有子类共性的方法:
int read()从输入流中读取数据的下一个字节。
int read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中。
void close() 关闭此输入流并释放与该流关联的所有系统资源。
java. io.FileInputStream extends InputStream
FileInputStream:文件字节输入流
作用:把硬盘文件中的数据,读取到内存中使用
构造方法:
FileInputStream(String name)
FileInputStream(File file)
参数:读取文件的数据源
String name:文件的路径
File file:文件
构造方法的作用:
1.创建一个FileInputStream对象
2.会把FileInputStream对象指定构造方法中要读取的方法
public class Demo02OutputStream {
public static void main(String[] args) throws IOException {
//读取文件一个字节
FileInputStream fis = new FileInputStream("D:\\IDEA\\Projects\\b.txt");
int len = fis.read();//读了一次后指针向后移动一位
System.out.println(len);
int len2 = fis.read();//读了一次后指针向后移动一位
System.out.println(len2);
//读取到了文件末尾返回-1,可用while循环
fis.close();
}
}
9.2.1一次读取多个字节
int read(byte[] b)
从输入流读取一定数量字节,存储在缓冲区数组b中
public static void main(String[] args) throws IOException {
//创建FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream(name: "09_ IOAndProperties\\b. txt");
//使用FileInputStream对象中的方法read读取文件
//int read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中。
byte[] bytes = new byte[2];
int len = fis.read(bytes);
System.out.println(len);//2
System.out.println(Arrays.toString(bytes)); //用Arrays.toString 就可打印整个数组
//释放资源
fis.close();
}
String类的构造方法
String(byte[] bytes) 把字节数组转换为字符串
String(byte[] bytes, int offset, int length) 把字节数组的一部分转换为字符串 offset为开始索引
读取多字节(一般一次性读1024)
byte[] bytes = new byte[1024];
int len = 0;
while(len=fis.read(bytes)!=-1){
System.out.println(new String(bytes,0,len)); //只接受有效的字节,防止浪费
}
fis.close;
9.2.2字节流【练习】
【文件复制】
/*
文件复制的步骤:
1.创建一个字节输入流对象,构造方法中绑定要读取的数据源
2.创建一个字节输出流对象,构造方法中绑定要写入的目的地
3.使用字节输入流对象中的方法read读取文件(在while循环条件内)
4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
5.释放资源,注意关闭的先后顺序
*/
public class Demo01CopyFile {
public static void main(String[] args) throws IOException {
long s = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("D:\\1.txt");
FileOutputStream fos = new FileOutputStream("D:\\ra3\\1.txt");
byte[] bytes = new byte[1024]; //一次读1024字节或整数倍,速度更快
int len = 0;
while ((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
}
long e = System.currentTimeMillis();
System.out.println("用时"+(e-s)+"毫秒")
}
9.3字符输入流Reader
有时候遇到中文读取显示不完整,因为中文字符可能占用多个字节,所以以字符为单位处理文本文件。
GBC 中文占2字节 utf-8 中文占3字节。
java.io.Reader
用于字符输入流的抽象类
public static void mian(String[] args) throws IOExeption{
FileReader fr =new FileReader("D:\\1,txt");
char[] cs = new char[1024];
int len = 0;
while((len=fr.read(cs))!=-1){
System.out.println(new String(cs, 0. len));
}
re.close();
}
9.4字符输出流Writer
java. io.Writer:字符输出流,是所有字符输出流的最顶层的父类,是-一个抽象类
共性的成员方法:
void write(int c)写入单个字符。
void write(char[] cbuf)写入字符数组。
abstract void write(char[] cbuf, int off, int len)写入字符数组的某-部分, ff数组的开始索引, len写的字符个数。
void write(String str)写入字符串。
void write(String str, int off, int len) 写入字符串的某一部分, off字符串的开始索引, len写的字符个数。
void flush( )刷新该流的缓冲。
void close() 关闭此流,但要先刷新它。
java. io. Filelwriter extends OutputStreamwriter extends Writer
Filewriter:文件字符输出流
作用:把内存中字符数据写入到文件中
构造方法:
FileWriter(File file)根据给定的File 对象构造一个Filewriter 对象。
Filelwriter(String fileName) 根据给定的文件名构造一个Filewriter 对象。
参数:写入数据的目的地
String fileName :文件的路径
File file:是一个文件
构造方法的作用:
1.会创建一-个FileWriter对象
2.会根据构造方法中传递的文件/文件的路径,创建文件
3.会把Filewriter对象指向创建好的文件
使用步骤:
- 创建FileWriter对象,构造方法中要绑定写入的数据的目的地
- 使用FileWriter 中的方法
write
, 把数据写入到内存缓冲区中(字符转换为字节的过程) - 使用FileWriter的方法
flush
, 把内存缓冲区的数据,刷新到文件中 - 释放资源(会把内存缓冲区的数据刷新到内存中),则第三步可以省略
public static void main(Styring[] args){
FileWriter fw = new FileWriter("");
fw.write(97); //此时数据在内存里,打卡开文件看不到
fw.flush();
fw.close();
}
9.4.1.close方法和flush方法
void flush( ) 刷新缓冲区,流对象可以继续使用。 void close() 先刷新缓冲区,然后通知系统释放资源。流对象不再使用。
9.4.2 续写和换行
/*
续写和换行
续写,追加写:使用两个参数的构造方法
Filewriter(String fileName, boolean append)
FileWriter(File file, boolean append)
参数:
String fileName,File file:写入数据的目的地
boolean append:续写开关 true:不会创建新的文件覆盖源文件,可以续写; false :创建新的文件覆盖源文件
换行:换行符号
windows: \r\n
linux:/n
mac:/r
*/
public class Demo04Writer {
public static void main(String[] args) throws IOException {
FileWriter fw = new Filewriter( "09_ IOAndProperties\\g.txt", true);
for(inti=0;i<10;i++){
fw. write("Helloworld"+i+"\r\n");
}
fw. close();
}
}
9.5IO异常处理
JDK7:在try的后边可以增加一一个(),在括号中可以定义流对象
那么这个流对象的作用域就在try中有效
try中的代码执行完毕,会自动把流对象释放,不用写finally
格式:
try(定义流对象;定义流对象....){
可能会产出异常的代码
}catch(异常类变量变量名){
异常的处理逻辑
}
try(//1.创建一个字节输人流对家,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream( name: “c:\\1.jpg");
//2.创建-一个字节输出流对象,构造方法中绑定要写入的目的地
File0utputStream fos = new File0utputStream( name: "d:\\1.jpg");){
//-次读取一个字节写入一一个字节的方式
//3.使用字节输入流对象中的方法read读取文件
int len = 0;
while(<len = fis.read())!=-1){
//4.使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中
fos .write(len);
}
}catch (IOException e){
System. out .println(e);
}
10.属性集
java.util.Properties extends Hashtable<k, v> implements Map<k,v>
Properties 类表示了一个持久的属性集,可保存在流中或从流中加载。属性列表的每个键及对应的值都是一个字符串。
Properties 集合是唯一一个和IO流相结合的集合
可以使用方法 store
把集合中的临时数据,持久化写入硬盘中存储
方法 load
,把硬盘中保存的文件(键值对),读取到集合中使用
属性列表中的每个键及其对应的值都是一个字符串。
Properties
集合是一个双列集合,key 和value默认是字符串。
使用Properties集合存储数据,遍历取出Properties集合中的数据
Properties集合是一个双列集合, key和value默认都是字符串
Properties集合有一些操作字符串的特有方法
object setProperty(String key, String value) 调用Hashtable的方法put。
String getProperty(String key) 通过key找到value值,此方法相当于Map集合中的get(key)方法
Set<string> stringPropertyNames() 返回此属性列表中的键集,其中该键及其对应值是字符串,此方法相当于Map集合中的keySet方法
基本使用
private static void show01(){
//创建Properties集合对象
Properties prop = new Properties();
//使用setProperty往集合中添加数据
prop.setProperty(k,v);
prop.setProperty();
prop.setProperty();
//使用stringPropertyNames 把集合中的键取出,存储到一个set集合中
Set<String> set = prop.stringPropertyNames();
//遍历set集合,输出
for(String key : set){
String value = prop.getProperty(key);
sout(key+" "+value);
}
}
与IO流集合
可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
void store (OutputStream out, String comments)
void store(Writer writer, String comments)
参数:
OutputStream out :字节输出流,不能写入中文
Writer writer :字符输出流,可以写中文
String comments :注释,用来解释说明保存的文件是做什么用的
不能使用中文,会产生乱码,默认是Unicode编码
一般使用”“空字符串
使用步骤:
1.创建Properties集合对象,添加数据
2.创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
4.释放资源
private static void show01(){
//创建Properties集合对象
Properties prop = new Properties();
//使用setProperty往集合中添加数据
prop.setProperty();
prop.setProperty();
prop.setProperty();
//创建字节输出流/字符输出流 ,构造方法中绑定要输出的目的地
FileWriter fw = new FileWriter("D:\\a.txt");
//使用Properties集合的方法store, 把集合中的临时数据,持久化写入到硬盘中
prop.store(fw, "save data"); //第二个关键字是comment
fw.close();
}
//保存的文件第一行有注释 save comment ,第二行有保存时间
load
方法 :把硬盘中保存的文件(键值对),读取到集合中使用。
/*
void load(InputStream inStream)
void load(Reader reader)
参数:
InputStream inStream : 字节输入流,不能读取含有中文的键值对
Reader reader : 字符输入流,能读取含有中文的键值对
使用步骤:
1.创建Properties集合对象
2.使用Properties集合对象的方法laod读取保存键值对的文件
3.遍历Properties集合
注意:
1.存储键值对的文件中,键与值默认的连接可以为空格,等于号
2.存储键值对的文件中,可以使用 # 注释。被注释的不会被读取
3.存储键值对的文件中,键与值默认都是字符串,不用再加上引号了
*/
private static void show03() throws IOException {
//1.创建Properties集合对象
Properties prop = new Properties();
//2.使用Properties集合对象中的方法load读取保存键值对的文件
prop.load(new FileReader( "09_ IOAndProperties\\prop.txt"));
//3.遍历Properties集合
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
String value = prop.getProperty(key);
System.out.println(key+"="+value);
}
注意用字符流FileReader
来读,不然容易出现中文乱码
11.缓冲流
字节 | 字符 | |
---|---|---|
输入(内存) | BufferedInputStream | BufferedReader |
输出(硬盘) | BufferedOutStream | BufferedWriter |
11.1字节缓冲输出流BufferedOutputStream
java. io. BufferedOutputStream extends outputStream
Buffered0utputStream :字节缓冲输出流
继承自父类的共性成员方法:
public void close() : 关闭此输出流并释放与此流相关联的任何系统资源。
public void flush() : 刷新此输出流并强制任何缓冲的输出字节被写出。
public void write(byte[] b): 将b. length字节从指定的字节数组写入此输出流。
public void write(byte[] b,int off, int len) :从指定的字节数组写入len字节, 从偏移量off开始输出到此输出流。
public abstract void write(int b) :将指定的字节输出流。
构造方法:
BufferedoutputStream(OutputStream out)创建一 个新的缓冲输出流,以将数据写入指定的底层输出流。
Bufferedoutputstream(OutputStream out, int size)创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输输出流
参数:
OutputStream out :字节输出流
我们可以传递FileOutputStream,缓冲流会给File0utputStream增加一-个缓冲区,提高FileOutputStream的写入效率
int. size:指定缓冲流内部缓冲区的大小,不指定默认
/*
使用步骤:
1.创建FileOutputStream 对象,构造方法中绑定输出的目的地
2.创建BufferedOutputStream对象,构造方法中传递FileOutputStream 对象对象,提高效率
3.使用BufferedOutputStream 的方法write ,把数据写入到内部缓冲区中
4.使用BufferedOutputStream 的方法flush,把缓冲区的数据刷新到文件中。
5.释放资源
*/
public static void main(String[] args){
FileOutputStream fos = new FileOutputStream("");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("我写入的数据");
bos.flush();
bos.close();
}
11.2字节缓冲输入流BufferedInputStream
继承自父类的成员方法:
int read()从输入流中读取数据的下一-个字节。
int read(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中。
void close() 关闭此输入流并释放与该流关联的所有系统资源。
构造方法:
BufferedInputStream( InputStream in)创建一个BufferedInputStream 并保存其参数,即输入流in, 以便将来使用。
BufferedInputStream(InputStream in, int size) 创建具有指定缓冲区大小的BufferedInputStream 并保存其参数,即输入流
参数:
InputStream in:字节输入流
我们可以传递FileInputStream,缓冲流会给FileInputStream增加一个缓冲区,提高FileInputStream的读取效率
int size:指定缓冲流内部缓冲区的大小,不指定默认
/*
使用方法:
1.创建FileUnputStream 对象,构造方法绑定要读取的数据源
2.创建BufferedInputStream 对象,其传递FileUnputStream 对象,提高FileInputStream的读取效率
3.使用方法read 读取文件
4.释放资源
*/
public static void main(String[] args){
FileInputStream fis = new FileInputStream("文件地址");
BufferedInputStream bis = new BufferedInputStream(fis);
int len = 0;
while((len = bis.read())!=-1){
System.out.println(len); //读出byte
}
bis.close(); //关闭缓冲流会自动关闭字节流
}
//读取多个字节
byte[] bytes = new byte[1024];
int len = 0;
while((len = bis.read(byte))!=-1){
System.out.println(new String(bytes, 0,len));
}
11.3字符缓冲输出流BufferedWriter
java.io.Bufferedwriter extends Writer
Bufferedwriter :字符缓冲输出流
继承自父类的共性成员方法:
void write(int c)写入单个字符。
void write(char[] cbuf)写入字符数组。
abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分, off数组的开始索引, len写的字符个数。
void write(String str)写入字符串。
void write(String str, int off, int len) 写入字符串的某一部分, off字符串的开始索引, len写的字符个数。
void flush()刷新该流的缓冲。
void close()关闭此流,但要先刷新它。
构造方法:
Bufferedwriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out, int sz) 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
参数:
Writer out :字符输出流
我们可以传递FileWriter,缓冲流会给Filewriter增加一个缓冲区,提高Filewriter的写入效率
int sz:指定缓冲区的大小,不写默认大小.
特有的成员方法:
void newLine() 写入一个行分隔符。会根据不同的操作系统,获取不同的行分隔符
/*
使用步骤:
1.创建字符缓冲输出流对象,构造方法中传递字符输出流
2.调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区中
3.调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据,刷新到文件中
4.释放资源
*/
public static void main(String[] args) throws IOEx ception{
BufferedWriter bw = new BufferedWriter(new FileWriter(""));
for(int i=0;i<10;i++){
bw.write("写入的字符");
//bw.write("\r\n");
bw.newLine(); //用这个换行更好
}
bw.close();
}
11.4字符缓冲输入流BufferedReader
java. io. BufferedReader extends Reader
继承自父类的共性成员方法:
int read() 读取单个字符并返回。
int read(char[] cbuf)一次读取多个字符, 将字符读入数组。
void close() 关闭该流并释放与之关联的所有资源。
构造方法:
BufferedReader(Reader in)创建一个使用默认大小输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz)创建一个使用指定大小输入缓冲区的缓冲字符输入流。
参数:
Reader in:字符输入流
我们可以传递FileReader,缓冲流会给FileReader增加一个缓冲区,提高FileReader的读取效率
特有的成员方法:
String readline() 读取一个文本行。读取一行数据
行的终止符号:通过下列字符之一即可认为某行已终止:换行('\n')、 回车('\r') 或回车后直接跟着换行(\r\n)。
返回值:
包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null
/*
使用步骤:
1.创建字符缓冲输入流对象,构造方法中传递字符输入流
2.使用字符缓冲输入流对象方法read/readLine 读取文本
3.释放资源
*/
public static void main(String[] args){
BufferedReader br = new BufferedReader(new FileReader(""));
while((line=br.readLine())!=null){
String line = br.readLine();
sout(line);
}
}
11.5【练习】
【文本排序】对于文本in.txt 。根据序号重新排序
3.第三句第三句第三句第三句第三句第三句第三句第三句第三句第三句第三句第三句第三句。
2.第二句第二句第二句第二句第二句。
5.第五句第五句第五句第五句第五句第五句第五句第五句第五句第五句第五句第五句第五句。
1.第一句第一句第一句第一句第一句。
4.第四句第四句第四句第四句第四句。
HashSet 是无序的,按照哈希值排序, 而已经给定的1,2,3,4刚好自动排下去
/*
练习:
对文本的内容进行排序
按照(1,2,3.... )顺序排序
分析:
1.创建一个HashMap集合对象,可以:存储每行文本的序号(1,2,3...);value:存储每行的文本
2.创建字符缓冲输入流对象,构造方法中绑定字符输入流
3.创建字符缓冲输出流对象,构造方法中绑定字符输出流
4.使用字符缓冲输入流中的方法readLine,逐行读取文本
5.对读取到的文本进行切割,获取行中的序号和文本内容
6.把切害好的序号和文本的内容存储到HashMap集合中(key序号是有序的,会自动排序1,2,3,4..)
7.遍历HashMap集合,获取每一个键值对
8.把每一个键值对,拼接为一个文本行
9.把拼接好的文本,使用字符缓冲输出流中的方法write,写入到文件中
10.释放资源
*/
public class Demo05Test {
public static void main(String[] args) throws IOException {
HashMap<String, String> map = new HashMap<>();
BufferedReader br = new BufferedReader(new FileReader("D:\\IDEA\\Projects\\src\\com\\exe\\demo01\\in.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\IDEA\\Projects\\src\\com\\exe\\demo01\\out.txt"));
String line;
while((line=br.readLine())!=null){
String[] arr = line.split("\\."); //切割完后返回数组
map.put(arr[0],arr[1]);
}
for(String key:map.keySet()){
String value = map.get(key);
line = key+"."+value;
bw.write(line);
bw.newLine();
}
bw.close();
br.close();
}
}
12.转换流
字符编码:自然语言字符和二进制数之间对应规则
- 解码: 字节–>字符
- 编码:字符–>字节
FileReader
类,用来读取字符文件的便捷类,此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在FileInputStream上构造一个InputStreamReader
FileReader
源码:
public FileReader(String fileName) throws FileNotFoundException{
super(new FileInputStream(fileName)); //读取底层字节再转换成字符
}
12.1InputStreamReader类
public class Input StreamReader extends Reader
InputStreamReader
是字节流通向字符流的桥梁:它使用指定的charset
读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,
或者可以接受平台默认的字符集。
每次调用InputStreamReader
中的一个read()方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层
流读取更多的字节,使其超过满足当前读取操作所需的字节。
java. io. InputStreamReader extends Reader
InputStreamReader:是字节流通向字符流的桥梁:它使用指定的charset 读取字节并将其解码为字符。(解码:把看不懂的变成能看懂的)
继承自父类的共性成员方法:
int read()读取单个字符并返回。
int read(char[] cbuf)- -次读取多个字符,将字符读入数组。
void close() 关闭该流并释放与之关联的所有资源。
构造方法:
InputStreamReader(InputStream in)创建一个使用默认字符集的 InputStreamReader.
InputStreamReader( InputStream in, String charsetName) 创建使用指定字符集的InputStreamReader。
参数:
InputStream in:字节输入流,用来读取文件中保存的字节
String charsetName :指定的编码表名称,不区分大小写,可以是utf-8/UTF-8, gbk/GBK... .不指定默认使用UTF-8
/*
使用步骤:
1.创建InputStreamReader 对象,构造方法中传递字节输入流和指定编码名称
2.使用InputStreamReader 对象的方法读取read文件
3.释放资源
注意事项:
构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码。
*/
public static void main(String[] args){
InputStreamReader isr = new InputStreamReader(new FileInputStream("这里注意文件和编码必须一致"),"utf-8");
int len = 0;
while((len=isr.read())!=-1){
System.out.println((char)len);
}
isr.close();
}
12.2OutputStreamWriter类
java. io. OutputStreamwriter extends Writer
OutputstreamWriter:是字符流通向字节流的桥梁:可使用指定的charset 将要写入流中的字符编码成字节。(编码:把能看懂的变成看不懂)
继续自父类的共性成员方法:
void write(int c)写入单个字符。
void write(char[] cbuf)写入字符数组。
abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分, off数组的开始索引, len写的字符个数。
void write(String str)写入字符串。
- void write(String str, int off, int len) 写入字符串的某一 部分, off字符串的开始索引, Len写的字符个数。
void flush( )刷新该流的缓冲。
- void close() 关闭此流,但要先刷新它。
构造方法:
OutputStreamWriter(OutputStream out )创建使用默认字符编码的OutputStreamwriter.
OutputStreamwriter(OutputStream out, String charsetName) 创建使用指定字符集的OutputStreamwriter.
参数:
outputstream out :字节输出流,可以用来写转换之后的字节到文件中
String charsetName :指定的编码表名称,不区分大小写,可以是utf-8/UTF-8, gbk/GBK, .. 不指定默认使用UTF-8
/*
使用步骤:
1.使用OutPutStreamWriter 对象,构造方法中传递字节输出流和制定的编码表名称
2.使用OutputStreamWriter对象的方法write, 把字符转换为字节存储缓冲区中(编码)
3.使用OutputStreamWriter对象的方法flush, 把内存缓冲区的字节刷新到文件中
4.释放资源
*/
public static void main(String[] args){
write_utf_8();
}
private static void write_utf_8() throws IOException{
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(""),"utf-8"); //第二参数默认是utf-8
osw.write("n你好胖");
osw.flush();
osw.close();
}
private static void write_jbk(){
}
12.3文件编码转换
将GBK的文件转化为utf-8文件
/*
分析:用读的转换流读GBK文件,再用utf-8的转换流写文件
*/
public class Dem0(){
public static void main(String[] args){
String srcFile = "源文件地址";
String destFile = "目标文件地址";
//创建流对象,
InputStreamReader isr = new InputStreamReader(new FileInputStream(srcFile),"GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destFile));
//读写数据
char[] cbuf = new char[1024];
int len;
while((len = isr.read())!=-1){
osw.write(cbuf);
}
osw.close();
isr.close();
}
}
13序列化
把对象以流的方式,写入到文件中保存,叫写对象,也叫对象的序列化
ObjectOutputStream
对象的序列化流 方法writeObject
ObjectInputStream
对象的反序列化流 方法 readObject
13.1序列化ObjectOutputStream
public static void main(String[] args){
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(""));
oos.writeObject(new person(name,age)); //由于Person类没有实现接口Serializable
oos.close();
}
此段代码运行报错 java.io.NotSerializableException
:当实例具有需要序列化接口时,抛出异常
public interface Serializable
: 类通过实现该接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。(标记)
13.2反序列化ObjectInputStream
java. io. objectInputStream extends InputStream
objectInputStream:对象的反序列化流
作用:把文件中保存的对象,以流的方式读取出来使用
构造方法:
objectInputStream( InputStream in)创建从指定InputStream 读取的object InputStream。
参数:
InputStream in:字节输入流
特有的成员方法:
object readObject() 从objectInputStream 读取对象。
使用步骤:
1.创建ObjectInputStream对象,构造方法中传递字节输入流
2.使用ObjectInputStream对象中的方法readObject读取保存对象的文件 返回对象接住
3.释放资源
4.使用读取出来的对象(打印)
public static void main(String[] args) throws IOException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(""));
Object o = ois.readObject(); //该方法有ClassNotFoundException
ois.close();
//对象的使用
}
13.3 transient关键字
static 关键字:静态关键字:
静态优先于非静态加载到内存中(静态变量优先于对象进入到内存),则说明静态变量不能被序列化
transient :瞬态关键字
transient修饰的变量不能被序列化()
13.4序列化失败冲突
问题:每次修改类的定义,都需要给class一个新的序列号,不然会报错
解决:无论对类的定义是否修改,都不要重新生成新的序列号
可以手动添加一个序列号
格式在Serializable接口中
定义对象的时候:
public class Person implements Serializable{
private static final long serialVersionUID = 1L; //注意一定是static final long 修饰的
...
}
13.5序列化集合【练习】
当我们想在文件中保存多个对象时,将多个对象存储到一个集合中,对集合进行序列化和反序列化
分析:
- 定义一个存储Person对象的ArrayList集合
- 往ArrayList集合存储Person对象
- 创建一个序列化流ObjectOutputStream对象
- 使用ObjectOutputStream对象的方法writeObject 对集合进行序列化
- 创建反序列化对象ObjectInputStream
- 使用ObjectInputStream对象的方法readObject 读取文件中保存的集合
- 把Object类型的集合转换为ArrayList类型。
- 遍历ArrayList集合
- 释放资源
public class Demo03Test {
public static void main(String[] args) throws IOException {
//1.定义一个存储Person对象的ArrayList集合
ArrayList<Person> list = new ArrayList<>();
//2.往Arraylist集合中存储Person对象
list. add(new Person( name: "张三", age: 18));
list .add(new Person( name: "李四”,age: 19));
list. add( new Person( name: "王五”,age: 20));
//3.创建- -个序列化流objectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream( ""));
//4.使用objectOutputStream对象中的方法write0bject,对集合进行序列化
oos . write0bject(list);
//5.创建一-个反序列化objectInputStream对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("");
//6.使用0bject InputStream对象中的方法readobject读取文件中保存的集合
Object o = ois.readobject();
//7.把object类型的集合转换为ArrayList类型
ArrayList<Person> list2 = (ArrayList<Person>)o;
//8.遍历ArrayList集合
for (Person p : list2) {
System.out.println(p);
}
ois.close();
oos.close();
}
14.打印流
java.io.printStream
:打印流
System.out.print
的out 就是打印流,print就是方法
PrintStream为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
PrintStream特点:
1.只负责数据的输出,不负责数据的读取
2.与其他输出流不同,PrintStream永远不会抛出 IOException
特有方法:print,println 输出任意类型的值
构造方法:
PrintStream(File file):输出的目的地是一个文件
PrintStream(Outputstream out ):输出的目的地是一个字节输出流
PrintStream(String fileName) :输出的目的地是-个文件路径
PrintStream extends OutputStream
继承自父类的成员方法:
public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
public void write(byte[] b): 将b. length字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len) :从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
public abstract void write(int b) : 将指定的字节输出流。
注意事项:
如果使用继承自父类的编码表,那么查看数据的时候会查询编码表
如果使用自己特有的方法print\println,写的数据原样输出
可以改变输出语句的目的地(打印流的去向)
输出语句,默认在控制台输出
System.setOut
静态方法将输出语句目的地改为参数传递的目的地。
public static void main(String[] args) throws FileNotFoundException{
System.out.println("我是在控制台输出");
PrintStream ps = new PrintStream("");
System.setOut(ps);
System.out.println("我是在打印流的目的地输出");
}
15.网络编程
15.1软件结构
C/S 结构 、B/S 结构
15.2网络通信协议
●网络通信协议:通过计算机网络可以使多台计算机实现连接,位于同一一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一 样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统-规定,通信双方必须同时遵守才能完成数据交换。
●TCP/IP协议 :传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它的内部包含一系列的用于处理数据通信的协议 ,并采用了4层的分层模型,每-层都呼叫它的下一-层所提供的协议来完成自己的需求。
15.3协议分类
java.net
包中提供了两种常见的网络协议的支持:
●UDP :用户数据报协议(User Datagram Protocol)。 UDP是无连接通信协议工即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一-两个数据包 ,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。UDP的交换过程如下图所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ff16RB7K-1620310966494)(C:\Users\祝金良\AppData\Roaming\Typora\typora-user-images\image-20210420151920034.png)]
特点:数据被限制在64kb以内,超出长度不发送。
●TCP :传输控制协议(Transmission Control Protocol)。 TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供子两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。
三次握手: TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
-
第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
-
第二次握手,服务器端向客户端回送一 个响应,通知客户端收到了连接请求。
-
第三次握手,客户端再次向服务器端发送确认信息,确认连接。整个交互过程如下图所示。
15.4网络编程要素
IP地址:
IPv4:32位
IPv6:128位,每16个字节一组,分为8组十六进制数ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
常用命令:
- 查看本机IP地址:
ipconfig
- 检查网络是否连通:
ping IP地址
- 本机IP地址:
127.0.0.1
、 localhost
端口号:是逻辑端口,无法直接看到,可以使用一些软件看到。(2字节,取值 0~65535)
打卡一个网络软件,os随机分配一个端口号,或者在打开的时候指定。
取值:1024前的系统分配出去了
常用: 80 网路端口 如www.baidu.com:80
3306 mysql 1521 oracle 8080 tomcat
议。UDP的交换过程如下图所示。
[外链图片转存中…(img-ff16RB7K-1620310966494)]
特点:数据被限制在64kb以内,超出长度不发送。
●TCP :传输控制协议(Transmission Control Protocol)。 TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供子两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。
三次握手: TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
-
第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
-
第二次握手,服务器端向客户端回送一 个响应,通知客户端收到了连接请求。
-
第三次握手,客户端再次向服务器端发送确认信息,确认连接。整个交互过程如下图所示。
15.4网络编程要素
IP地址:
IPv4:32位
IPv6:128位,每16个字节一组,分为8组十六进制数ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
常用命令:
- 查看本机IP地址:
ipconfig
- 检查网络是否连通:
ping IP地址
- 本机IP地址:
127.0.0.1
、 localhost
端口号:是逻辑端口,无法直接看到,可以使用一些软件看到。(2字节,取值 0~65535)
打卡一个网络软件,os随机分配一个端口号,或者在打开的时候指定。
取值:1024前的系统分配出去了
常用: 80 网路端口 如www.baidu.com:80
3306 mysql 1521 oracle 8080 tomcat