目录
一、IO流
一、File类的使用
-
File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。
如果需要访问文件内容本身,则需要使用输入/输出流。
-
想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录。
-
File对象可以作为参数传递给流的构造器
1.常用构造器
-
public File(String pathname)
以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。
绝对路径:是一个固定的路径,从盘符开始
相对路径:是相对于某个位置开始
-
public File(String parent,String child)
以parent为父路径,child为子路径创建File对象。
-
public File(File parent,String child)
根据一个父File对象和子文件路径创建File对象
举例说明:
@Test
public void test1(){
//构造器1
File file1 = new File("hello.txt");//相对于当前module
File file2 = new File("E:\\Me\\src\\study1\\he.txt");
System.out.println(file1);
System.out.println(file2);
//构造器2:
File file3 = new File("D:\\workspace_idea1","JavaSenior");
System.out.println(file3);
//构造器3:
File file4 = new File(file3,"hi.txt");
System.out.println(file4);
}
2.路径分隔符
-
路径中的每级目录之间用一个路径分隔符隔开。
-
路径分隔符和系统有关:
windows和DOS系统默认使用“\”来表示
UNIX和URL使用“/”来表示
-
Java程序支持跨平台运行,因此路径分隔符要慎用。
-
为了解决这个隐患,File类提供了一个常量:
public static final String separator。根据操作系统,动态的提供分隔符。
File file1 = new File("d:\\wushen\\info.txt");
File file2 = new File("d:" + File.separator + "wushen" + File.separator + "info.txt")
File file3 = new File("d:/wushen");
3.常用方法
-
File类的获取功能
public String getAbsolutePath():获取绝对路径
public String getPath() :获取路径
public String getName() :获取名称
public String getParent():获取上层文件目录路径。若无,返回null
public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
public long lastModified() :获取最后一次的修改时间,毫秒值
public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组
-
File类的重命名功能
public boolean renameTo(File dest):把文件重命名为指定的文件路径
-
File类的判断功能
public boolean isDirectory():判断是否是文件目录 public boolean isFile() :判断是否是文件 public boolean exists() :判断是否存在 public boolean canRead() :判断是否可读 public boolean canWrite() :判断是否可写 public boolean isHidden() :判断是否隐藏
-
File类的创建功能
public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。 如果此文件目录的上层目录不存在,也不创建。 public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建 注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目路径下。
-
File类的删除功能
public boolean delete():删除文件或者文件夹 删除注意事项: Java中的删除不走回收站。 要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录
二、IO流原理
-
输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
-
输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。
三、流的分类
1. 按操作数据单位不同分为:字节流,字符流
- 字节流(8 bit):是一个字节一个字节的操作。二进制操作。操作任意类型的文件。
直接从数据源或目的地读写数据- 字符流(16 bit):是一个字符一个字符的操作。一个字符两个字节,主要用来处理文本文件。.txt,.java,.py,.xml,.properties,.html,.css,.js, 不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
2. 按数据流的流向不同分为:输入流,输出流
- 输入流:从硬盘上读取数据到内存。(读)
- 输出流:从内存写出数据到硬盘。(写)
一个文件在传输过程中经历了多次拷贝,IO性能本身就很低。
零拷贝、Nio附加题!!!
3. 按流的角色的不同分为:节点流,处理流
- 节点流:直接操作一个特定的IO设备。
- 处理流:在节点流的基础上,做进一步的处理。
4. IO 流体系
字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 | |
抽象基类 | InputStream | InputStream | Reader | Writer |
访问文件 (节点流) | FileInputStream | FileOutputStream | FileReader | FileWriter |
缓冲流 (处理流) | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
操作对象 | ObjectInputStream | ObjectOutputStream |
5. 作用
输入流:就是一点一点的往内存中读数据!
字节输入流:
1.创建一个FileInputStream对象
2.定义一个标记,用来控制输入流的读取
3.循环读取,如果读取到了-1,说明读取到了文件的末尾,循环结束
4.关闭资源。*****
注意:我们发现一个流读完了就没有了,不能再读了。
当一个流读完之后会默认调用mark和reset方法来进行记录和重置,
这个流就已经重置到了上次读完的位置,
所以就无法再次读取内容。并不是读完一次之后就关闭了流。
public class Ch02 {
@Test
public void test02() {
InputStream inputStream = null;
try {
inputStream = new FileInputStream("e:/aaa.txt");
int read;
byte [] buf = new byte[1024];
while((read = inputStream.read(buf)) != -1) {
System.out.println(new String(buf));
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
IOUtil.closeIO(inputStream,null);
}
@Test
public void test01() {
InputStream inputStream = null;
try {
inputStream = new FileInputStream("e:/aaa.txt");
// 开始读的操作,read方法,返回值是int,当返回值为-1时,说明文件读取到了末尾
// 读取文件是否结束的标记
int read;
// 字节流读数据的时候一个字节一个字节去读
// 循环读取
while((read = inputStream.read()) != -1) {
System.out.print(read + " ");
}
System.out.println();
System.out.println("读取完毕,再读一次。。。。");
// 字节流读数据的时候一个字节一个字节去读
// 循环读取
while((read = inputStream.read()) != -1) {
System.out.print(read + " ");
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
// 关闭流
inputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
字节输出流
FileOutputStream构造器:
boolean append参数:如果传入true,则代表在原有基础上追加,不覆盖
如果传入false,或者不传,覆盖原有内容写的操作,目标文件如果不存在,会自动新建。
public class Ch03 {
@Test
public void test03(){
System.out.println(Objects.nonNull("null"));
}
@Test
public void test02() {
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream("e:/aaa.txt",true);
// 一个字节一个字节的写
outputStream.write("\r\n".getBytes());
outputStream.write("八月正午的阳光都没你耀眼".getBytes());
System.out.println("数据写出成功...");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
IOUtil.closeIO(null,outputStream);
}
}
@Test
public void test01() {
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream("e:/aaa.txt", true);
// 一个字节一个字节的写
outputStream.write(98);
System.out.println("数据写出成功...");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
outputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
在jdk1.7之后,很多资源类实现了AutoCloseable接口
包括我们常见的流,FileInputStream,FileOutputStream....
可以在try中定义资源,并会主动释放资源
了解即可!!
public class Ch04 {
public static void main(String[] args) throws FileNotFoundException {
try(InputStream inputStream = new FileInputStream("e:/aaa.txt");
OutputStream outputStream = new FileOutputStream("e:/bbb.txt",true)){
byte [] buf = new byte[3];
int len;
while((len = inputStream.read(buf))!= -1){
outputStream.write(buf,0,len);
}
System.out.println("文件复制完成...");
}catch (IOException e){
e.printStackTrace();
}
}
}
文件的复制、字节型
两个流:
FileInputStream:把对应文件的内容读取出来
FileOutputStream:把读到的内容写出去
read(byte[])
write(byte[])
public class Exam {
@Test
public void test01() throws IOException {
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream =null;
int len;
int write;
byte[] buf = new byte[1024];
try {
fileInputStream = new FileInputStream("D:\\aaa.txt");
fileOutputStream =new FileOutputStream("D:\\bbb.txt");
while ((len=fileInputStream.read(buf))!=-1) {
fileOutputStream.write(buf);
}
System.out.println("文件复制完毕");
}catch (IOException e){
e.printStackTrace();
}finally {
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
文件的复制、字符型
public class Examm {
@Test
public void testReaderFileWriter() {
Reader reader = null;
Writer writer = null;
try {
//创建File类的对象,指明读入和写出的文件
reader = new FileReader("D:/aaa.txt");
writer = new FileWriter("D:/aaa.txt");
//数据的读入和写出操作
char[] cbuf = new char[5];
int len;//记录每次读入到cbuf数组中的字符的个数
while((len = reader.read(cbuf)) != -1){
//每次写出len个字符
writer.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流资源
try {
if(writer != null)
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(reader != null)
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
缓冲流
字符处理流(用的最多)
只能处理纯文本文件:
.txt,.java,.html,.css.........
利用缓冲字符流来写一个文件的复制
public class Ch06 {
@Test
public void test02() {
BufferedWriter bufferedWriter = null;
try {
bufferedWriter = new BufferedWriter(new FileWriter("e:/xxx.txt"));
bufferedWriter.write("今天是星期二,天气凉爽!");
System.out.println("数据写出成功!");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
IOUtil.closeIO(null,bufferedWriter);
}
}
@Test
public void test01() {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader("e:/aaa.txt"));
String str;
while((str = bufferedReader.readLine()) != null) {
System.out.println(str);
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
IOUtil.closeIO(bufferedReader,null);
}
}
}
二、序列化
序列化与反序列化:操作对象
- 序列化:将对象写入到IO流中,将内存模型的对象变成字节数字,可以进行存储和传输。
- 反序列化:从IO流中恢复对象,将存储在硬盘上或者从网络中接收的数据恢复成对象模型
- 使用场景:所有可在网络上传输的对象都必须是可序列化的,否则会报错,所有保存在硬盘上的对象也必须要可序列化。
- 序列化版本号:
- 反序列化必须拥有class文件,但随着项目的升级,class文件也会升级
- 序列化保证升级前后的兼容性。
- java序列化提供了一个版本号
- 版本号是可以自由指定,如果不指定,JVM会根据类信息自己计算一个版本号,所以无法匹配,则报错!!!
- 不指定版本号,还有一个隐患,不利于JVM的移植,可能class文件没有改,但是不同的jvm计算规则不一样,导致无法反序列化
- 如果只修改了方法,反序列化是不受影响,无需修改版本号
- 修改了静态变量static,瞬态变量transient,反序列化也不受影响,无需修改版本号
总结:
1.所有需要网络传输的对象都需要实现序列化接口
2.对象的类名、实例变量都会被序列化;方法、类变量、transient变量不会被序列化
3.如果想让某个变量不被序列化,可以用transient修饰
4.序列化对象的引用类型成员变量,也必须是可序列化的,否则会报错
5.反序列化时必须有序列化对象的class文件
6.同一个对象被序列化多次,只有第一次序列化为二进制流,以后都只是保存序列化的版本号
7.建议所有可序列化的类加上版本号,方便项目升级。
public class Ch01 {
@Test
public void test02() {
ObjectInputStream objectInputStream = null;
// 先锁定一个文件
try {
objectInputStream = new ObjectInputStream(new FileInputStream("e:/user.txt"));
User user = (User) objectInputStream.readObject();
System.out.println("对象读取成功:" + user);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} finally {
IOUtil.closeIO(objectInputStream,null);
}
}
@Test
public void test01() {
ObjectOutputStream objectOutputStream = null;
// 先锁定一个文件
try {
objectOutputStream = new ObjectOutputStream(new FileOutputStream("e:/user.txt"));
User user = new User("张三",25,1);
objectOutputStream.writeObject(user);
System.out.println("对象写出成功...");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
IOUtil.closeIO(null,objectOutputStream);
}
}
}
我们最终会把所有的.class文件打包,把这个包部署到服务器上。
从始至终,.java仅仅是我们程序员写的,给程序员看的。
.java甚至不会参与到打包中,不会出现在服务器上。
运维人员去服务器部署项目,部署的就是一堆的.class。
我们的.properties属性文件是不参与编译的。
public class Ch02 {
public static void main(String[] args) throws IOException {
File file = new File("db.properties");
Properties properties = new Properties();
properties.load(new FileInputStream(file));
System.out.println(properties.getProperty("username"));
}
}