复习(偏重点)
java.sql.Date和java.util.Date的联系和区别
- 都代表一个时间类型,util代表java程序中的时间类型、sql是数据库对接的时间类型
- 父类:util.Date,子类sql.Date
- 精确度不一样,util.Date到年月日时分秒,sql.Date只到年月日
String类型转换成日期类型
:(后面会常用)
sql.Date可通过方法valueOf(“年-月-日”)进行字符串的转换。
util.Date通过SimpleDateFormat对象的parse(“时分秒年月日”);方法进行字符串的转换
File类(偏重点,要会用)
可对目录(文件夹)或文件进行一些列操作(不包括文件内容的操作)
文件目录分隔符:
File.separator、\\、/
文件实例化:
实例化方法 | 说明 |
---|---|
File file = new File(目录或文件的路径) | 直接创建文件对象 |
File file = new File(目录路径+“\\”+目录或文件名); | 目录后拼接一个文件名 |
File file = new File(目录路径+File.separator+目录或文件名); | 目录后拼接一个文件名 |
File file = new File(目录路径,目录或文件名); | 目录后拼接一个文件名,省去上面那种打/了 |
可直接输出查看文件路径,或exists查看文件是否存在 |
文件对象的方法:
实例化文件对象后的方法 | 说明:要在实例化File f = new File(文件路径);之后再用f.进行调用 | 返回值 |
---|---|---|
获取功能: | ||
getAbsolutePath() | 返回File的绝对路径名 | String |
getPath() | 将此File转换为路径名(实例化时的值) | String |
getName() | 返回此File表示的文件或目录的名称,不包含上级文件 | String |
length() | 返回此File表示的文件的字节大小,不能获取目录的字节大小 | long |
getParent() | 返回此File表示的父目录的路径名字符串,没有则null | String |
toString() | 返回此File表示的路径字符串 | String |
判断功能: | ||
exists() | 此File标识的文件或目录是否实际存在 | boolean |
isDirectory() | 此File标识的是否为文件夹(目录) | boolean |
isFile() | 此File表示的是否为文件 | boolean |
isHidden() | 此File表示的是否为隐藏的文件或目录 | boolean |
canWrite() | 此File表示的文件或目录是否可写 | boolean |
canRead() | 此File表示的文件或目录是否可读 | boolean |
equals(Object obj) | 将指定对象与调用函数的对象进行比较 | boolean |
删除和创建 | ||
createNewFile() | 仅当不存在该名称的文件时,创建 一个新的空文件 ,不存在返回false | boolean |
mkdir() | 创建 由File表示的目录 | boolean |
mkdirs() | 创建由File表示的目录,包括任何必须但不存在的父目录 | boolean |
delete() | 删除由此File表示的文件或目录 只能删除文件或者空目录,不能删除非空目录 | boolean |
renameTo(new File(x)) | 更改文件位置到x下 | void |
遍历 | ||
list() | 返回一个String数组,表示该File目录中的所有子文件或目录的名称 | String[] |
listFiles() | 返回一个File数组,表示File目录中的所有子文件或目录的路径 | File[] |
看下面代码:
@Test
public void test01() {
//字符串中路径的写法:
// File file = new File("D:\\用户-常\\Desktop\\test.txt");
// File file1 = new File("D:/用户-常/Desktop/test.txt");
File file2 = new File("D:"+File.separator+"用户-常"+File.separator+"Desktop"+File.separator+"test.txt");//自动添加路径,不确定是什么平台时用
System.out.println(file2.getName());//获取文件名
System.out.println(file2.getPath());//获取文件路径
System.out.println(file2.getParent());//获取上层文件路径
System.out.println(file2.length());//长度
System.out.println(file2.exists());//是否存在
System.out.println(file2.isFile());//是不是文件(false是文件夹)
System.out.println(file2.isDirectory());//是不是文件夹(false是文件)
}
//例子:给一个路径,将该路径下的所有文件和子目录(缩进后输出子文件)
@Test
public void test02(){
show(0,"D:\\13214");
}
public static void show(int level, String url){//目录才行
File file = new File(url);
if (file.isDirectory()){
File[] files = file.listFiles();//该目录下的所有文件和目录
for (File f: files) {//获取每个子文件和子目录
for (int i = 0; i < level; i++) {//遍历进行缩进
System.out.print("\t");
}
System.out.println(f);//输出文件名
if (f.isDirectory()){
show(level+1,f.getAbsolutePath());//传入绝对路径
}
}
}
}
IO流(重点)
关闭流要求:一定要关闭输入输出流,满足后开的先关,先开的最后关
,不要关错流,不关会一直占用内存
学习IO流是为了文件的上传和下载
数据库存(严格符合要求的标准数据):变量、数组、集合等信息
文件里存(可通过IO流读与写文件数据):图片、视频、文本等信息
(后期文件和下载有指定的工具类,不用写IO流,直接读取服务器的数据,写入到自己本地)
什么是IO流?
input:输入流(读)
output:输出流(写)
流:管道(位于内存和物理文件之间输送信息),可持续化数据
IO流的步骤:
获得源数据对象
(创建一个File类的对象,还可能是别的对象)创建流
,(创建一个输入或输出流的对象)让流和源数据对象相连
(流(源数据对象),在输出流的源数据对象后true追加写入,否则会清空原内容)通过流进行读和写文件
(输入流对象的read()/输出流的write()方法)关闭流
(各种流对象的close(); )
节点流(重点)
输入流的优点:(网上找的)
- 是Java标准库中提供的类,可以很方便地读取文本文件中的数据。
输入流的缺点:(网上找的)
- 在读取文件时,文件必须存在,否则会抛出
FileNotFoundException
异常。
输出流的优点:(网上找的)
- 它可以非常方便地将数据写入文件中。
输出流的缺点:(网上找的)
- 如果文件不存在会自动创建一个新文件。
字节流
以字节为单位进行数据操作,一般用来处理图片、视频、音频PPT、Word等类型的文件。(二进制,8位字节为单元)
字节输入流FileInputStream(读)
构造方法(不能有中文) | 说明 |
---|---|
FileInputStream fi = new FileInputStream(String fileName) | 接受一个文件名字符串来创建一个FileInputStream对象 |
FileInputStream fi = new FileInputStream(File file) | 接受一个File对象来创建一个FileInputStream对象 |
FileInputStream方法 | 说明 | 返回值 |
---|---|---|
read() | 读取一个数据字节,如果已经到达文件末尾,返回-1 | int |
read(byte[] b) | 将最多 b.length 个字节的数据读入到数组b中 | int |
read(byte[] b,int off,int len); | off开始读取len个字节的数据读入到数组b中 | int |
close() | 关闭输入流 | void |
available() | 从此输入流中读取的剩余字节数,大于0则输入流中有内容 可用于遍历的条件判断,有缓冲流连要用缓冲流的(要少用) | int |
转字符串:
String sum = "";
int i;
while((i = fi.read()) != -1) {
sum += (char) i;
}
字节输出流FileOutputStream(写)
可在最后加true表示在文件末尾追加写入(不覆盖)默认为false
注意:不写true就会清空文件内容`
构造方法(不能有中文) | 说明 |
---|---|
FileOutputStream fo = new FileInputStream(String fileName[,true]) | 接受一个文件名字符串来创建一个FileOutputStream对象,(true追加,否则会清空文件内容) |
FileOutputStream fo = new FileOutputStream(File file[,true]) | 接受一个File对象来创建一个FileOutputStream对象,(true追加,否则会清空文件内容) |
FileOutputStream方法 | 说明 | 返回值 |
---|---|---|
write(int b) | 将单个字节写入流中 | void |
write(byte[] b) | 将字节数组指定位置的子数组写入到流中 | void |
write(byte[] b,int off,int len) | 将字节数组指定位置的子串写入到流中 | void |
flush() | 仅仅是刷新缓冲区,强制写出缓冲区的数据 | void |
close() | 关闭输出流 | void |
字符流
以字符为单位进行数据操作,一般用来处理纯文本类型的文件,如.txt文件等,无法直接写入字节数据
字符输入流FileReader(读)
构造方法FileReader | 说明 |
---|---|
FileReader fr = new FileReader(String fileName) | 接受一个文件名字符串来创建一个FileReader对象 |
FileReader fr = new FileReader(File file) | 接受一个File对象来创建一个FileReader对象 |
FileReader方法 | 说明:必须按上面实例化之后 | 返回值 |
---|---|---|
read() | 会返回读取到的字符编码,如果已经到达文件末尾,返回-1 | int |
read(char[] ch) | 这个方法会读取长度为ch.length 的字符到cbuf 中,并返回读取的字符个数 | int |
close() | 关闭输入流 | void |
字符输出流FileWriter(写)
可在最后加true表示在文件末尾追加写入(不覆盖)默认为false
注意:不写true就会清空文件内容`
构造方法 | 说明 |
---|---|
FileWriter(File file[,true]) | 接受一个File对象,创建一个新的文件写入流,如果该文件已经存在,将被覆盖。(true追加,否则会清空文件内容) |
FileWriter(String fileName[,true]) | 接受一个文件名字符串,创建一个新的文件写入流,如果该文件已经存在,将被覆盖。(true追加,否则会清空文件内容) |
FileWriter(File file, boolean append[,true]) | 可以设置是否追加内容到文件末尾,(true追加,否则会清空文件内容) |
FileWriter(String fileName, boolean append[,true]) | 可以设置是否追加内容到文件末尾,(true追加,否则会清空文件内容) |
FileWriter(FileDescriptor fd[,true]) | 创建一个与已存在文件关联的文件写入流。(true追加,否则会清空文件内容) |
FileWriter方法 | 更多操作方法说明:必须按上面实例化之后 | 返回值 |
---|---|---|
write(int c) | 将单个字符(根据ascii码转的)写入流中 | void |
write(char[] ch, int off, int len) | 将字符数组指定位置的子数组写入到流中 | void |
write(String str, int off, int len) | 将字符串指定位置的子串写入到流中 | void |
flush() | 仅仅是刷新缓冲区,强制写出缓冲区的数据 | void |
close() | 关闭输出流 | void |
自写快捷循环语句:
for(int i = 输入流对象.read();i != -1;i = 输入流对象.read()){
System.out.print((char)i);
}
快捷创建循环
close()
和flush()
的区别:
- ``close()
是关闭流对象,但是会先刷新一次缓冲区,关闭之后,流对象不可以继续再使用了,否则报空指针异常。
- ``flush()
仅仅是刷新缓冲区,准确的说是**"强制写出缓冲区的数据"**,流对象还可以继续使用。
看下面字节流读取和写入的步骤:
//例1:读取文件下的内容
@Test
public void test01() throws IOException {
//获得数据源对象
File file = new File("D:/用户-常/Desktop/test.txt");
//创建一个流并连接数据源:
//从外部物理文件读入到内存里,用输入流
//文件里都是字母和数字,没有汉字,就用字节流
//不需要额外功能,选择用节点流
// FileReader fileReader = new FileReader(file);//能读取汉字
FileInputStream fileInputStream = new FileInputStream(file);//流连接到数据源
//读取一个字符
int read = fileInputStream.read();
//循环读取全部内容,含回车
while (read != -1){
System.out.print((char)read);
read = fileInputStream.read();
}
/*下面代码代表上面循环的几行
for(int read = fileInputStream.read();read != -1;read = fileInputStream.read()){
System.out.print((char)read);
}*/
//关闭流
fileInputStream.close();
}
//例2:控制台接收内容,将内容写入到文件里
@Test
public void test02() throws IOException {
//获得数据源对象
File file = new File("D:/用户-常/Desktop/test.txt");
//创建一个流并连接数据源:
FileOutputStream fileOutputStream = new FileOutputStream(file,true);//流连接到数据源,true是追加输入(不覆盖)
//提示信息,接收控制台输入的信息
System.out.println("请输入内容(不能为汉字):");
String str = new Scanner(System.in).next();
//接收信息,写入到数据源对象里,(会覆盖文件原内容)
fileOutputStream.write(str.getBytes());
//关闭流
fileOutputStream.close();
System.out.println("写入成功");
}
看下面字符流读取和写入的步骤:
@Test
public void test01() throws IOException {
FileReader fileReader = null;
try {
//获取数据源对象:
File file = new File("D:/用户-常/Desktop/test.txt");
//创建流,读取文本要用字符流
//读取视频图片音频要用字节流
fileReader = new FileReader(file);
//读取数据
int read = fileReader.read();
while (read != -1){
System.out.print((char)read);
read = fileReader.read();
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
//关闭流
fileReader.close();
}
}
//字符输出流一样
@Test
public void test02() throws IOException {
FileWriter fileWriter = null;
try {
File file = new File("D:/用户-常/Desktop/test.txt");
fileWriter = new FileWriter(file,true);//追加输入
fileWriter.write("\n哈哈哈");
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
fileWriter.close();
}
}
处理流之缓冲流(偏重点)
缓冲流就是为字节、字符流提速的工具
是为高效率而设计的 (以前是一个字节一个字节的读,现在可以控制一起读)
缓冲字节流 | 缓冲字符流 |
---|---|
缓冲字节输入流BufferedInputStream(读) | 缓冲字符输入流BufferedReader(读) |
缓冲字节输出流BufferedOutputStream(写) | 缓冲字符输出流BufferedWriter(写) |
每个的构造方法都是传入对应的输入输出流对象(套娃)
例:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:123/t.txt"));
BufferedOutputStream bos =new BufferedOutputStream(new FileOutputStream("D:t.txt",true));
BufferedReader br = new BufferedReader(new FileReader("D:123/t.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:123/t.txt",true));
缓冲输入流的遍历方法:
for(int s = 缓冲输入流对象.read(); s!=-1; s = 缓冲输入流对象.read()){
System.out.print((char或byte)s);
}
byte[] bytes = new byte[自定义大小];
while (缓冲输入流.read(bytes) != -1){
缓冲输出流.write(bytes);//这行一般都是bytes的操作
}
//下面少用,本地用可以
byte[] bytes = new byte[自定义大小];
while (BufferedInputStream对象.available() > 0){//只能BufferedInputStream对象使用
缓冲输出流.write(bytes,0,缓冲输入流.read(bytes));
}
特殊:(了解)
实例化时可以指定缓冲区大小
BufferedInputStream(InputStream in, int size)
BufferedOutputStream(OutputStream out, int size)
BufferedReader(Reader in, int sz)
BufferedWriter(Writer out, int sz)
BufferedInputStream也有available()方法,上上个代码就是,(有点可能有bug少用)
特殊:
BufferedReader br = new BufferedReader(new FileReader("D:123/t.txt"));
for(String s = br.readLine(); s!=null; s = br.readLine()){//按行读取,不读换行符
System.out.println(s);
}
BufferedWriter的换行符bw.newLine(); 写一行分隔符,由系统属性定义符号
看下面缓冲字节流的复制图片的代码:
@Test
public void test01() throws IOException {//就测试一下,没写trycatch
File file = new File("D:\\用户-常\\Desktop\\test.jpg");
File file2 = new File("D:\\用户-常\\Desktop\\新建文件夹\\test.jpg");
FileInputStream fileInputStream = new FileInputStream(file);//流连接到数据源
FileOutputStream fileOutputStream = new FileOutputStream(file2,true);//流连接到数据源,true是追加输入(不覆盖)
//创建处理流管道:
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);//设置缓冲区大小
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
byte[] bytes = new byte[1000000];
while (bufferedInputStream.read(bytes) != -1){
bufferedOutputStream.write(bytes);
}
//关闭流,关闭要求:后开的先关,先开的最后关
bufferedOutputStream.close();
bufferedInputStream.close();
fileOutputStream.close();
fileInputStream.close();
System.out.println("复制成功");
}
看下面自己写的BufferedReader和BufferedWriter使用方法
@Test
public void test02() throws IOException {
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader("D:/用户-常/Desktop/test.txt"),1024);
bw = new BufferedWriter(new FileWriter("D:/用户-常/Desktop/test.txt",true));
for(String s = br.readLine(); s!=null; s = br.readLine()){//按行读取,不读换行符
System.out.println(s);
}
/*for(int s = br.read(); s!=-1; s = br.read()){
System.out.print((char)s);
}*/
char[] chars = "asjdoasjdiojasid".toCharArray();
bw.newLine();//换行
bw.write(chars);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
bw.close();
br.close();
}
}
保存控制台输入的信息到文件里,按行实时转入:
@Test
public void test() throws IOException {//保存控制台输入的信息
BufferedWriter bw = null;//设置了缓冲区
try {
bw = (new BufferedWriter(new FileWriter("D:\\用户-常\\Desktop\\t.txt",true),1024));
Scanner sc = new Scanner(System.in);
System.out.println("请输入要保存的文件内容,输入exit退出");
String str = sc.next();
while (!"exit".equals(str)){
bw.write(str);
bw.newLine();//换行
str = sc.next();
bw.flush();//弹出缓冲区的内容,观察t.txt文件每次输入都有信息录入进去
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
bw.close();
}
}
一个字节一个字节的方式、不使用缓冲字节输入输出流的方式一次读取多个字节、使用缓冲字节输入输出流
下面代码参考:[[Java IO流之缓冲流(深入浅出学习) - LeeHua - 博客园 (cnblogs.com)](https://www.cnblogs.com/liyihua/p/12269827.html)]
/**
* 不使用缓冲字节输入输出流,
* 一个一个字节的方式。(最慢)
*/
public static void method1() throws IOException {//没用trycatch
FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/test.jpg");
FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/copy1.jpg");
int len = 0;
while ((len = fis.read()) != -1) {
fos.write(len);
}
fis.close();
fos.close();
}
/**
* 不使用缓冲字节输入输出流,
* 一次读取多个字节的方式。(中等)
*/
public static void method2() throws IOException {
FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/test.jpg");
FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/copy2.jpg");
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
fis.close();
fos.close();
}
/**
* 使用缓冲字节输入输出流(最快)
*/
public static void method3() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/test.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/copy3.jpg"));
byte[] bytes = new byte[1024];
int len = 0;
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
bos.close();
bis.close();
}
看自己写的递归的方式完成目录中所有文件及子目录的复制
import java.io.*;
public class Test {
public static void main(String[] args) {
try {
copyDirectory("D:\\用户-常\\Desktop","D:\\用户-常\\Desktop\\新建文件夹\\啊哈哈\\test");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void copyFile(File file1,File file2) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file1));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file2));
byte[] test = new byte[1024];
for (int read = bis.read(test); read > 0; read--) {
bos.write(test,0, test.length);
}
bos.close();
bis.close();
}
public static void copyDirectory(String Directory1,String Directory2) throws IOException{
File file1 = new File(Directory1);
File file2 = new File(Directory2);
/*if (!file1.exists() || !file1.isDirectory()){
System.out.println("你要复制的目录不存在或路径不存在");
return;
}*/
if (!file2.exists()){//不存在就多级创建
file2.mkdirs();
}
File[] files = file1.listFiles();
for (File file : files) {
if (file.isFile()){
System.out.println("进来了");
File file3 = new File(Directory2,file.getName());
copyFile(file,file3);
}
if (file.isDirectory()){
copyDirectory(file.getAbsolutePath(),file2.getAbsolutePath()+File.separator+file.getName());
}
}
}
}
其他(了解)
处理流之转换流:
InputStreamReader、OutputStreamWriter将字节流和字符流进行转换。 属于处理流的转换流
了解下面代码即可
public static void main(String[] args) throws IOException {
//使用输入字节流--转换流/FileReader--缓冲字符流
//将index文件复制到.txt文件里
FileInputStream fis = new FileInputStream("D:\\用户-常\\Desktop\\index.html");
InputStreamReader isr = new InputStreamReader(fis);//字符流,没缓冲功能
BufferedReader br = new BufferedReader(isr);
FileOutputStream fos = new FileOutputStream("D:\\用户-常\\Desktop\\t.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bw = new BufferedWriter(osw);
//边读边写
String s = br.readLine();
while (s!= null){
bw.write(s);
bw.newLine();
s = br.readLine();
}
bw.close();
osw.close();
fos.close();
br.close();
isr.close();
fis.close();
}
/*
【转换流】
目的:将字节流转换成字符流来使用
输入字节流--转换流---缓冲字符流
*/
处理流之数据流:
DataInputStream、DataOutputStream用来对基本数据类型和字符串进行操作
了解下面代码即可
@Test
public void test() throws IOException {
//数据流:属于节点流,不能直接跟数据源关联
//创建数据源
File file = new File("D:\\用户-常\\Desktop\\t.txt");
//创建管道流
FileOutputStream fos = new FileOutputStream(file);
DataOutputStream dos = new DataOutputStream(fos);
//使用数据流写入带数据类型的信息
dos.writeInt(99);
dos.writeBoolean(false);
dos.writeDouble(87.5);
dos.writeUTF("吉林");
//关闭流
dos.close();
fos.close();
}
@Test
public void test1() throws IOException {
File file = new File("D:\\用户-常\\Desktop\\t.txt");
FileInputStream fis = new FileInputStream(file);
DataInputStream dis = new DataInputStream(fis);
//只能按插入时的顺序读,类型要一样
System.out.println("刚才写入的整型是:"+dis.readInt());
System.out.println("刚才写入的布尔是:"+dis.readBoolean());
System.out.println("刚才写入的小数是:"+dis.readDouble());
System.out.println("刚才写入的字符串是:"+dis.readUTF());
//关闭流
dis.close();
dis.close();
}
/*
【数据流】存入和取出的信息是带变量类型的,(不能直接跟数据源关联,和字节输入输出流关联)
输送基本数据类型的,在输送的过程中会始终保存信息的变量类型。
*/
处理流之对象流:
ObjectInputStream,ObjectOutputStream用于存储和读取基本数据类型数据或对象的处理流。
它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
序列化和反序列化:
ObjectOutputStream 类 : 把内存中的Java对象转换成平台无关的二进制数据,从而允许把这种二进制数据持久地保存在磁盘上,或通过网络将这种二进制数据传输到另一个网络节点。---->序列化
ObjectInputStream类 : 当其它程序获取了这种二进制数据,就可以恢复成原来的Java对象。---->反序列化
注意:
(1)被序列化的类的内部的所有属性,必须是可序列化的 (基本数据类型都是可序列化的)
(2)transient修饰的属性不会被序列化存储(始终是默认值)。
(3)static修饰的属性只会保存最后传入的值(因为是静态共享资源)。
如果一个类想要实现序列化操作
1.实现序列化Serializable接口
2.添加序列号id,下面是添加序列号id的方法
了解下面代码即可
@Test
public void test() throws Exception{
//获取数据源
File file = new File("D:\\用户-常\\Desktop\\t.txt");
//创建管道流对象
FileOutputStream fos = new FileOutputStream(file,true);
ObjectOutputStream oos = new ObjectOutputStream(fos);
//写入信息
Student s1 = new Student(1,"常","男");
Student s2 = new Student(2,"常哲","男");
oos.writeObject(s1);//会报没有序列化,Student要实现Serializable标记接口,不用重写
oos.writeObject(s2);
//关闭流
oos.close();
fos.close();
}
@Test
public void test0() throws Exception{
File file = new File("D:\\用户-常\\Desktop\\t.txt");
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
while (fis.available()>0){//要拿输入流的这个方法看还有没有数据
Object o = ois.readObject();
if (o instanceof Student){
Student s = (Student) o;
System.out.println(s.toString());
}
}
//拿出时Student类的内容变化(例如加了个方法),就会出错
//需要给一个码:
/*Student s = (Student) ois.readObject();
System.out.println(s);
Student s1 = (Student) ois.readObject();
System.out.println(s1);*/
ois.close();
fis.close();
}
import java.io.Serializable;
/**
* Serializable是允许当前类对象进行序列化操作
* 实现了这个接口,没有任何方法需要重写,目的就是标记作用
* 如果一个类想要实现序列化操作2.实现序列化接口2.添加序列号id
*/
public class Student implements Serializable {
private static final long serialVersionUID = -5352494921384421054L;
private int id;
private String name;
private String gender;
public Student(int id, String name, String gender) {
this.id = id;
this.name = name;
this.gender = gender;
}
public Student() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", gender=" + gender +
'}';
}
}
节点流之打印流(了解)
PrintStream:System.out就是一个PrintStream类型的对象。
System.in : “标准”输入流。—》默认情况下 从键盘输入
System.out : “标准”输出流。 —》默认情况下,输出到控制台。
了解下面代码即可
@Test
public void test() {
//获得数据源对象,默认控制台
//创建管道流对象
PrintStream stream = System.out;//输出流
stream.println("吉林");
stream.close();
}
@Test
public void test0() throws IOException {
InputStream input = System.in;
int read = input.read();//接收一个数据
System.out.println("键盘输入了" + (char) read);//结果
input.close();
}
@Test
public void test1() throws IOException {
//扫描器
// Scanner sc = new Scanner(System.in);//扫描键盘输入的信息
Scanner sc = new Scanner(new FileInputStream("D:\\用户-常\\Desktop\\记事本.txt"));//扫描D:下的信息
while (sc.hasNext()){
System.out.println(sc.next());
}
sc.close();
}
面试题(重点)
1. 输入流和输出流联系和区别,节点流和处理流联系和区别(解释+举例子)
首先,你要明白什么是“流”。直观地讲,流就像管道一样,在程序和文件之间,输入输出的方向是针对程序而言,向程序中读入东西,就是输入流,从程序中向外读东西,就是输出流。输入流是得到数据,输出流是输出数据。
而节点流,处理流是流的另一种划分,按照功能不同进行的划分。节点流,可以从或向一个特定的地方(节点)读写数据。处理流是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。
2. 字符流字节流联系区别;什么时候使用字节流和字符流? (解释+举例子)
字符流和字节流是流的一种划分,按处理照流的数据单位进行的划分。两类都分为输入和输出操作。在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成。这四个都是抽象类。字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。字节流是最基本的,所有的InputStrem和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的 但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的编码来处理,也就是要进行字符集的转化 这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联的。
面试题二(重点)
1. 列举常用字节输入流和输出流并说明其特点,至少5对。
FileInputStream 从文件系统中的某个文件中获得输入字节。
ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。
FilterInputStream 包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。FilterInputStream 类本身只是简单地重写那些将所有请求传递给所包含输入流的 InputStream 的所有方法。FilterInputStream 的子类可进一步重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段。
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。
StringBufferInputStream此类允许应用程序创建输入流,在该流中读取的字节由字符串内容提供。应用程序还可以使用ByteArrayInputStream 从 byte 数组中读取字节。 只有字符串中每个字符的低八位可以由此类使用。
ByteArrayOutputStream此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。
FileOutputStream文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。文件是否可用或能否可以被创建取决于基础平台。特别是某些平台一次只允许一个 FileOutputStream(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。
FilterOutputStream类是过滤输出流的所有类的超类。这些流位于已存在的输出流(基础 输出流)之上,它们将已存在的输出流作为其基本数据接收器,但可能直接传输数据或提供一些额外的功能。 FilterOutputStream 类本身只是简单地重写那些将所有请求传递给所包含输出流的 OutputStream 的所有方法。FilterOutputStream 的子类可进一步地重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段。
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。
PipedOutputStream可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于毁坏状态。
2. 说明缓冲流的优点和原理(重点)Buffer
不带缓冲的流的工作原理:它读取到一个字节/字符,就向用户指定的路径写出去,读一个写一个,所以就慢了。带缓冲的流的工作原理:读取到一个字节/字符,先不输出,等凑足了缓冲的最大容量后一次性写出去,从而提高了工作效率
优点:减少对硬盘的读取次数,降低对硬盘的损耗。
3. 序列化的定义、实现和注意事项(重点)
想把一个对象写在硬盘上或者网络上,对其进行序列化,把他序列化成为一个字节流。
实现和注意事项:
- 实现接口Serializable Serializable接口中没有任何的方法,实现该接口的类不需要实现额外的方法。
- 如果对象中的某个属性是对象类型,必须也实现Serializable接口才可以
- 序列化对静态变量无效
- 如果不希望某个属性参与序列化,不是将其static,而是transient
- 串行化保存的只是变量的值,对于变量的任何修饰符,都不能保存
- 序列化版本不兼容
4. 使用IO流完成文件夹复制(结合递归)
import java.io.*;
/*
* CopyDocJob定义了实际执行的任务,即
* 从源目录拷贝文件到目标目录
*/
public class CopyDir2 {
public static void main(String[] args) {
try {
copyDirectiory("d:/301sxt","d:/301sxt2");
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* 复制单个文件
* @param sourceFile 源文件
* @param targetFile 目标文件
* @throws IOException
*/
private static void copyFile(File sourceFile, File targetFile) throws IOException {
BufferedInputStream inBuff = null;
BufferedOutputStream outBuff = null;
try {
// 新建文件输入流
inBuff = new BufferedInputStream(new FileInputStream(sourceFile));
// 新建文件输出流
outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));
// 缓冲数组
byte[] b = new byte[1024 * 5];
int len;
while ((len = inBuff.read(b)) != -1) {
outBuff.write(b, 0, len);
}
// 刷新此缓冲的输出流
outBuff.flush();
} finally {
// 关闭流
if (inBuff != null)
inBuff.close();
if (outBuff != null)
outBuff.close();
}
}
/*
* 复制目录
* @param sourceDir 源目录
* @param targetDir 目标目录
* @throws IOException
*/
private static void copyDirectiory(String sourceDir, String targetDir) throws IOException {
// 检查源目录
File fSourceDir = new File(sourceDir);
if(!fSourceDir.exists() || !fSourceDir.isDirectory()){
return;
}
//检查目标目录,如不存在则创建
File fTargetDir = new File(targetDir);
if(!fTargetDir.exists()){
fTargetDir.mkdirs();
}
// 遍历源目录下的文件或目录
File[] file = fSourceDir.listFiles();
for (int i = 0; i < file.length; i++) {
if (file[i].isFile()) {
// 源文件
File sourceFile = file[i];
// 目标文件
File targetFile = new File(fTargetDir, file[i].getName());
copyFile(sourceFile, targetFile);
}
//递归复制子目录
if (file[i].isDirectory()) {
// 准备复制的源文件夹
String subSourceDir = sourceDir + File.separator + file[i].getName();
// 准备复制的目标文件夹
String subTargetDir = targetDir + File.separator + file[i].getName();
// 复制子目录
copyDirectiory(subSourceDir, subTargetDir);
}
}
}
}