黑马程序员 <a href="http://www.itheima.com" target="blank">java培训</a>
第二十二天笔记
1.内存操作流的概述和讲解
源 FileIInputStream FileReader它们的源就是文件
目的地:FileOutputStream FileWriter它们的目的地就是文件。
BufferedInputStream 是输入流,它的源是 InputStream.
BufferedOutputStream是输出流 它的目的地 OutputStream.
对于内存操作流,它们的源与目的地就是内存。
简单说,它是数据是从内存中读取来的,写入的目的地也是内存。
一共有三对
ByteArrayInputStream ByteArrayOutputStream 对byte[]操作
CharArrayReader CharArrayWriter 对char[]操作
StringReader StringWriter 对String操作
介绍ByteArrayOutputStream
它的底层是一个byte[]数组,这个流是一个输出流,简单说,它写入的数据就写入到了底层的byte[]中。我们可以使用toByteArray()方法来获取底层写入的数据.
public class ByteArrayDemo { public static void main(String[] args) throws IOException { // 通过ByteArrayOutputStream来完成数据写入内存,并将写入的数据获取到. // 1.创建ByteArrayOutputStream ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 2.写入数据 baos.write("hello world".getBytes()); // 将数据写入到底层的byte[]中。 // 3.获取底层的byte[] byte[] b = baos.toByteArray(); // baos.close(); //对于这个流来说,它操作的就是内存,所以不需要关闭. //通过ByteArrayInputStream来获取内存中的数据 ByteArrayInputStream bais=new ByteArrayInputStream(b); //从b中读取数据 int code=-1; while((code=bais.read())!=-1){ System.out.print((char)code); } } }
2.打印流的概述和特点
对于我们要学的打印流它只有输出。
我们学习的打印流有两个
PrintWriter 字符打印流
PrintStream 字节打印流
问题:PrintWriter打印流的目的地是哪?
- 可以是文件
- 可以是另一个字节输出流
- 可以是另一个字符输出流
特点总结:
- 只能输出,也就是说只有目的地
- 它可以自动刷新,需要设置
- 它可以操作文件或其它的流
- 可以操作所有数据类型.
3.PrintWriter作用Writer的子类使用
1.创建一个PrintWriter
PrintWriter pw = new PrintWriter("a.txt");
BufferedWriter bw = new BufferedWriter(pw); // 将PrintWriter使用BufferedWriter来包装
public class PrintWriterDemo1 { public static void main(String[] args) throws IOException { demo3(); } // 使用PrintWriter来完成向文件中输出操作 public static void demo1() throws FileNotFoundException { // 1.创建一个PrintWriter PrintWriter pw = new PrintWriter("a.txt"); // 2.输出(打印) pw.write("hello"); pw.write("world"); pw.write("good"); // 3.关闭 pw.close(); } // 我们使用BufferedWriter来对PrintWriter包装 public static void demo2() throws IOException { // 1.创建一个PrintWriter PrintWriter pw = new PrintWriter("a.txt"); BufferedWriter bw = new BufferedWriter(pw); // 将PrintWriter使用BufferedWriter来包装 // 2.输出(打印) bw.write("hello"); bw.newLine(); bw.write("world"); bw.newLine(); bw.write("good"); // 3.关闭 bw.close(); } // 关于print与write方法区别 public static void demo3() throws FileNotFoundException { // 创建一个流,向a.txt写入数据 PrintWriter pw = new PrintWriter("a.txt"); // 写入 // pw.write(97); pw.print(97); // 关闭 pw.close(); } }
4.PrintWriter实现自动刷新和换行
通过源代码来分析怎样实现.
class PrintWriter{
Boolean autoflush; //定义一个可用于控制是否自动刷新
Public PrintWriter(xxx,Boolean autoflush){
This.autoflush=autoflush;
}
在这个类中提供了大量的write方法
又提供了大量的print方法
它有一个比较特殊的方法
Println()在这个方法中直接执行newLine();
也就是说,带ln的方法是可以自动换行的。
在newLine方法中执行换行 后,会判断autoflush是否为true,如果为true,会自动刷新。
}
总结:对于PrintWriter来说,它的自动刷新与换行只有在设置了autoflush=true,并且调用println(xxx)方法才可以实现。
5.标准输入输出流概述和输出语句的本质
标准输入设备:键盘
标准输出设备:显示器
标准输入流:从键盘读取信息。
标准输出流:向屏幕输出信息
标准输出流是:System.out
标准输入流是:System.in
6.三种方式实现键盘录入
A.Scanner sc=new Scanner(System.in);
这种方式只有在jdk1.5后才可以使用.
B.使用io流来操作
System.in可以读取数据.
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.in 是一个从键盘读信息的字节输入流
我们使用InputStreamReader对System.in包装,就可以一次读取一个字符或多个字符。
在使用BufferedReader来包装一次,就可以一次读取一行信息.
C.是使用命令行参数
就是利用了main方法的参数
//使用System.in来从键盘读取数据 public class SystemINAndOutDemo2 { public static void main(String[] args) throws IOException { InputStream is = System.in; // 通过System.in获取的是一个InputStream,但是InputStream是abstract类 // 也就是说,其实返回的真实类型应该是InputStream的一个子类. // 一次读取一个字节 //int code = is.read(); //read方法是一种阻塞式的方法,如果没有读到信息会等待,只有读到了信息才会向下执行. //System.out.println((char) code); //一次读取多个信息 byte[] b=new byte[5]; int len=is.read(b); //一次最多可以读取5个字节 System.out.println(new String(b,0,len)); } }
7.输出语句用字符缓冲流改进
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
8.随机访问流概述和写出数据
RandomAccessFile类的父类是Object,它虽然是IO体系中,但是它与InputStream OutputStream Reader Writer无关系.
我们使用这个类可以对文件进行随机读写操作。
通过API我们需要知道:
- 这个流是可以进行读写操作
- 它有一个文件指针,用于记录读写操作的位置。(相当于索引)
- 我们可以获取文件指针位置以及对文件指针进行跳转设置 .
作用: 在做断点续传时可以使用。
通过RandomAccessFile类的构造方法,在创建时指定其模式,就可以设置读写.
"r" |
以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。 |
"rw" |
打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 |
"rws" |
打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。 |
"rwd" |
打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。 |
public class RandomAccessFileDemo1 { public static void main(String[] args) throws IOException { // writeMsg(); readMsg(); } // 读操作 public static void readMsg() throws IOException { // 1.创建一个RandomAccessFile对象 RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw"); // 可读可写 // 2.读数据 //System.out.println(raf.readBoolean()); //System.out.println(raf.readChar()); //System.out.println(raf.readInt()); raf.seek(1); //从头开始跳过几个字节 System.out.println(raf.readChar()); //文件指针跳过了两个 raf.skipBytes(4); //从当前位置开始向后跳4个字节 System.out.println(raf.readUTF()); // 3.关闭 raf.close(); } // 写操作 public static void writeMsg() throws IOException { // 1.创建一个RandomAccessFile对象 RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw"); // 可读可写 // 2.写数据 raf.writeBoolean(true); System.out.println(raf.getFilePointer());// 1 raf.writeChar('a'); System.out.println(raf.getFilePointer()); // 3 raf.writeInt(10); System.out.println(raf.getFilePointer());// 7 raf.writeUTF("中国人"); // utf-8码一个汉字使用3个字节,writeUTF方法在写之前会先使用两个字节来记录数据长度 System.out.println(raf.getFilePointer());// 18 // 3.关闭 raf.close(); } }
9.序列化和反序列化流的概述和使用
我们说的序列化流也是对象流ObjectInputStream ObjectOutputStream
对于我们在网络或文件中要传输的对象,它们必须是可序列化的。
ObjectOutputStream可以将一个对象写入到网络或文件
ObjectInputStream可以从网络或文件中读取一个对象。
一个对象需要被其它人使用,我们就可以将对象直接通过流传递。
只有可以被序列化的对象数据才可以存储到文件中或在网络中传递。
注意:如果通过对象流将一个对象写入到文件或在网络中传输,就要求,对象必须是可序列化的。
10.如果解决序列化时候的黄色警告线问题
就是没有给我们的类添加一个serialVersionUID,如果添加了,这没有警告线.
问题:开发中所有的类都需要有serialVersionUID吗?
在开发中需要这个标识的是实体类。简单说,是在网络中传输的这些对象会需要。
11.如果让对象的成员变量不被序列化
在类中的static的数据是不被序列化的。
使用transient修饰符来修饰的变量也不会被序列化
public class SequenceInputStreamDemo2 { public static void main(String[] args) throws IOException { // 1.创建一个可以读取part1.txt文件的流 FileInputStream fis1 = new FileInputStream("part1.txt"); // 2.创建一个可以读取part2.txt文件的流 FileInputStream fis2 = new FileInputStream("part2.txt"); // 3.创建一个可以读取part3.txt文件的流 FileInputStream fis3 = new FileInputStream("part3.txt"); // 4.创建一个集合,Vector将所有的读取文件的流装入 Vector<FileInputStream> v = new Vector<FileInputStream>(); v.add(fis1); v.add(fis2); v.add(fis3); // for(Enumeration enums=v.elements();enums.hasMoreElements();){ // enums.nextElement(); // } Enumeration<FileInputStream> enums = v.elements(); SequenceInputStream sis = new SequenceInputStream(enums); // 5.创建一个文件输出流 FileOutputStream fos = new FileOutputStream("part.txt"); int code = -1; while ((code = sis.read()) != -1) { fos.write(code); } // 6.关闭 fos.close(); sis.close(); } }
12.Properties的概述和作为Map集合的使用
在开发中,我们说的Properties它其实指的是一个配置文件。
这种配置文件的特点是键值对映射
而我们在jdk中有一个Properties类,它其实就是一个map集合。
关于java.util.Properties类的用法:
就像Map一样就可以
13.Properties的特殊功能使用
Properties这个类虽然是一个Map,但是它没有泛型,原因,是它的key与value都是String类型。
我们真正在使用Properties方法是一般不使用put get keyset这样的方法,我们一般使用这个类中提供的一些特殊的方法:
String getProperty(String key) --------相当于map中的get方法。
Object setProperty(String key,Stirng value)---相当于map中的put方法.
public Set<String> stringPropertyNames()---相当于map中的keySet方法
14.Properties的load和stor e list功能
我们的Properties它可以与io流一起使用
load----它是从properties文件中将数据直接封装到Properties对象中.(读操作)
list---它是将Properties对象中的数据直接写入到properties文件中(写操作)
store方法是用于修改数据.