javaFile类与I/O流
1.File类的使用
/**
* @ClassName: java高级进阶
* @Description:File类的使用
*
* 1.File类的一一个对象,代表-一个文件或一一个文件 目录(俗称:文件夹)
* 2.File类声明在java. io包下
* 3. File类中涉及 到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,
* 并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成。
* 4.后续Filej类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点".
**/
public class FileTest {
/*
如何创建File类的实例
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对象
2.路径分隔符
windows: \ \
unix:/
*/
@Test
public void test(){
//内存层面的对象
//构造器1
File file = new File("hello.txt");//相对于当前module 相对路径
File file2 = new File("G:\\OneDrive\\OneDrive - sdtbu.edu.cn\\java知识准备\\java编程源码\\java高级进阶\\src\\com\\test\\IO\\he.txt");//绝对路径
System.out.println(file);
System.out.println(file2);
//构造器二
File file3 = new File("G:\\OneDrive\\OneDrive - sdtbu.edu.cn\\java知识准备\\java编程源码\\java高级进阶\\src\\com\\test\\IO","he");//文件目录
System.out.println(file3);
//构造器三
File file4 = new File(file3,"he.txt");//文件目录
System.out.println(file4);
}
/*
获取操作:
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数组
public boolean renameTo(File dest): 把文件重命名为指定的文件路径
比如: file1. renameTo(file2)为例:返回布尔值
要想保证返回true,需要file1在硬盘中是存在的,且file2不能在硬盘中存在。
*/
/*
判断功能
public boolean isDirectory(): 判断是否是文件目录
public boolean isFile() :判断是否是文件
public boolean exists() :判断是否存在
public boolean canRead() :判断是否可读
public boolean canWrite() :判断是否可写
public boolean isHidden() :判断是否隐藏
*/
/*
创建硬盘中对应的文件或文件目录
public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false
public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。
public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建。
删除磁盘中的文件或文件目录
public boolean delete(): 删除文件或者文件夹
删除注意事项:
Java中的删除不走回收站。
*/
}
package com.fq.lz.Day21.Day20_3_IO;
import java.io.File;
import java.io.IOException;
/**
* @author GoodTime0313
* @version 1.0
* @Description File类表示文件
* @date 2021/3/25 14:39
*/
public class FileDemo1 {
public static void main(String[] args) throws IOException {
//File表示硬盘中的一个文件
//1.创建
//1.1 调用构造方法创建File对象(文件可以存在也可以不存在)
File file = new File("file_1.txt");
//1.2 如果文件不存在,创建
if (!file.exists()) {
boolean newFile = file.createNewFile();
System.out.println("创建的结果"+newFile);
}else{
System.out.println("文件已存在");
}
System.out.println("-------------------");
//2.删除
//2.1 直接删除
//boolean delete = file.delete();
//System.out.println("删除的结果:" + delete);
//2.2 JVM退出时删除 void
// file.deleteOnExit();
System.out.println("-------------------");
//3.获取
//3.1 获取相对路径
System.out.println(file.getPath());
//3.2 获取相对路径
System.out.println(file.getAbsolutePath());
//3.3 获取名称
System.out.println(file.getName());
//3.4 获取文件大小
System.out.println(file.length());
//3.5 获取最后一次修改的时间
System.out.println(file.lastModified());
System.out.println("-------------------");
//4.判断
//4.1 是不是文件
System.out.println(file.isFile());
//4.2 是不是隐藏的
System.out.println(file.isHidden());
//4.3 是不是可读
System.out.println(file.canRead());
//4.4 是不是可写
System.out.println(file.canWrite());
//5. 重命名
System.out.println(file.renameTo(new File("file_2.txt")));
//可以实现剪切功能 改位置,改文件名
//System.out.println(file.renameTo(new File("d:/file_2.txt")));
}
}
/**
* @author GoodTime0313
* @version 1.0
* @Description File表示硬盘中的目录(文件夹)
* @date 2021/3/25 15:10
*/
public class FileDemo2 {
public static void main(String[] args) {
//1.创建
//1.1 创建File对象,并指定一个目录
File file = new File("c.txt");
System.out.println(file.toString());
//1.2 创建目录
if (!file.exists()) {
//单级目录
file.mkdir();
//多级目录
file.mkdirs();
} else {
System.out.println("目录已经存在");
}
//2.删除
//2.1 直接删除 只能删除最深层的,必须是空目录
System.out.println(file.delete());
//2.2 JVM来删除
// file.deleteOnExit();
//3.获取
System.out.println(file.getPath());
System.out.println(file.getAbsolutePath());
//最里层的目录
System.out.println(file.getName());
//4.判断
//4.1 是不是文件夹
System.out.println(file.isFile());
System.out.println(file.isHidden());
System.out.println(file.isAbsolute());
//5.重命名:只是该最底层的文件夹,父目录不存在为false
System.out.println(file.renameTo(new File("d.txt")));
//6.遍历目录
//6.1 获取当前目录下的文件夹和文件夹名
String[] list1 = file.list();
for (String s : list1) {
System.out.println(s);
}
//6.2 按条件过滤文件
String[] list = file.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
//return true 符合要求 false 不符合要求
if (name.endsWith(".jpg")) {
return true;
}
return false;
}
});
//6,3 获取当前目录下的文件夹和文件夹名 (file数组)
File[] files = file.listFiles();
for (File file1 : files) {
System.out.println(file1.getName());
}
//6.4 获取当前目录下的文件
File[] files1 = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.getName().endsWith(".jpg")) {
return true;
}
return false;
}
});
}
}
案例1:递归遍历文件夹
/**
* @author GoodTime0313
* @version 1.0
* @Description 递归遍历文件夹
* @date 2021/3/25 16:11
*/
public class FileDemo1 {
public static void main(String[] args) {
File file = new File("E:\\百度网盘文件\\a");
listDir(file,0);
}
public static void listDir(File file,int level) {
File[] files = file.listFiles();
System.out.println(getSeparator(level)+file.getName());
level++;
if (files != null && files.length > 0) {
for (File file1 : files) {
if (file1.isDirectory()) {
listDir(file1,level);
} else {
System.out.println(getSeparator(level)+file1.getName());
}
}
}
}
public static String getSeparator(int level){
if (level == 0){
return "";
}
StringBuilder builder = new StringBuilder();
for (int i = 0; i < level; i++) {
builder.append("___");
}
return builder.toString();
}
}
案例2:递归删除文件夹
/**
* @author GoodTime0313
* @version 1.0
* @Description 递归删除文件夹
* @date 2021/3/25 16:31
*/
public class FileDemo2 {
public static void main(String[] args) {
File file = new File("E:\\百度网盘文件\\a");
listDeleteDir(file);
}
public static void listDeleteDir(File file) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File file1 : files) {
if (file1.isDirectory()) {
listDeleteDir(file1);
} else {
file1.delete();
}
}
}
file.delete();
}
}
File类的限制,只能看见文件或文件夹的大小,名字等,但是里面的内容控制不了。
[wppay]
2.IO流简单介绍
什么是流?
流的分类
按数据的流向:
- 输入流 input:文件->内存
- 输出流 output:内存->文件
按处理的数据单位:
- 字节流(byte 8bit 图片视频等非文本)
- 字符流(char 16bit 文本):所有的字符都有一个编码
按流的功能:
- 节点流(直接作用于文件的流),具有实际传输数据的读写功能。
- 处理流(已有的流之上包了一层),在节点流的基础之上增强功能
/**
* 3.抽象基类 不能实例化,具体实现由其子类
* (抽象基类) 字节流 字符流
* 输入流 InputStream Reader
* 输出流 OutputStream Writer
*
* 4.流的体系结构
* 抽象基类 节点流(或文件流) 缓冲流(处理流的-种)
* InputStream FileInputStream BufferedInputStream
* OutputStream FileOutputStream BufferedOutputStream
* Reader FileReader BufferedReader
* Writer Filewriter BufferedWriter
*
* 5.具体操作基本按四步走,例题上面有显示。
**/
3.节点流的使用
3.1 字符流
字符编码
所有的字符流都有缓存区
FileReader
public class FileReaderDemo {
public static void main(String[] args) throws Exception {
//使用字符流读取文件
//1.创建FileReader对象
FileReader reader = new FileReader("a.txt");
//2.读取
//2.1 单个字符读取
/*int data;
while ((data = reader.read()) != -1) {
System.out.print((char) data);
}*/
//2.2 读取多个字符
char[] data = new char[5];
int num;
while ((num = reader.read(data)) != -1) {
String s = new String(data, 0, num);
System.out.println(s);
}
//3.关闭
reader.close();
}
}
Filewriter
public class FileWriterDemo {
public static void main(String[] args) throws Exception {
//1.创建流
FileWriter fw = new FileWriter("a.txt");
//2.写入文件
for (int i = 0; i < 10; i++) {
fw.write("写入写入\n");
fw.flush();
}
//3.关闭
fw.close();
}
}
例一:将FileReader.txt文件内容读入程序中,并输出到控制台
@Test
public void testFileReader(){//相较于当前Module
FileReader reader = null;
try {
//1.实例化File类的对象,指明要操作的文件
File file = new File("FileReader.txt");
//2.提供具体的操作
reader = new FileReader(file);
//3.数据的读入过程 一个一个读取
//read():返回读入的一个字符。如果达到文件末尾,返回-1
//方式一:
// int read = reader.read();
// while (read!=-1){
// System.out.print((char) read);
// read = reader.read();
// }
//方式二:语法上的修改
int read;
while((read = reader.read())!= -1){
System.out.print((char) read);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//垃圾回收机制只回收JVM堆内存里的对象空间。
//对其他物理连接比如数据库连接、输入流输出流、Socket连接无能为力
//4.流的关闭操作
try {
if (reader!=null){
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意
public static void main(String[] args) {
File file = new File( "hello. txt");//在main函数中实例化File类的对象,指明要操作的文件是相较于当前工程
}
说明点:
1.reader.read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1。
2.异常的处理:为了保证流资源-定可以执行关闭操作。需要使用try-catch-finally处理,写的时候可以先抛出异常,最后按上述的1,2,3,4步骤将1,2,3全部添加进try-catch,finally中去关闭流。
3.读入的文件一定要存在,否则就会报FileNotFoundException。
例二:在例一下,对read()操作升级:使用read的重载方法,一次读取一个数组的字符
@Test
public void testFileReader1(){
FileReader reader = null;
try {
//1. File类的实例化
File file = new File("FileReader.txt");
//2. FileReader流的实例化
reader = new FileReader(file);
//3.读入的操作(数据很多时 不能一个一个读)
//read(char[] cbuf): 返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1
char[] cbuf = new char[5];
int len;
while ((len = reader.read(cbuf))!=-1){
//方法一:
//这里一定要写len 若为cbuf.length会读取不正确
//每次读取是覆盖前面 若缺少时 之前的内容无法覆盖也会显示
// for (int i = 0; i < len; i++) {
// System.out.print(cbuf[i]);
// }
//String错误的写法
// String str =new String(cbuf);
// System. out. print(str);
//String正确的方法 从头开始取 每次取len个
String str = new String(cbuf, 0, len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源的关闭
try {
if (reader!=null){
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
例三:从内存中写出数据到硬盘的文件里。
说明:
1.输出操作,对应的File可以不存在的。如果不存在,在输出的过程中,会自动创建此文件。 2.File对应的硬盘中的文件如果存在: . FileWriter writer = new FileWriter(file,false); //覆盖 默认 FileWriter writer = new FileWriter(file,true);//追加
@Test
public void testFileWriter() {
FileWriter writer = null;
try {
//1.提供File类的对象,指明写出到的文件
File file = new File("FileWriter.txt");
//2.提供FileWriter的对象,用于数据的写出
writer = new FileWriter(file,true);
//3.写出的操作
writer.write("i have a dream!\n");
writer.write("i need!\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流资源的关闭
try {
if(writer!=null){
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
综合:字符流读写操作结合
/*
字符流读写操作结合
不能使用字符流来处理图片等字节数据
*/
@Test
public void test4(){
FileReader fr = null;
FileWriter fw = null;
try {
//1.创建File类的对象,指明读入和写出的文件
File srcFile = new File("FileReader.txt");
File destFile = new File("FileWriter.txt");
//2.创建输入流和输出流的对象
fr = new FileReader(srcFile);
fw = new FileWriter(destFile);
//3.数据的读入和写出操作
char[] cbuf = new char[5];
int len;
while ((len = fr.read(cbuf))!=-1){
fw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流资源
try {
if (fr!=null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fw!=null) {
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
结论:
1.对于文本文件(. txt, .java,.c.cpp),使用字符流处理
2.对于非文本文件(. jpg, . mp3, . mp4, .avi,.doc,.ppt....), 使用字节流处理
3.2 字节流
new FileOutputStream("name")会产生一个新文件;
new FileInputStream("name")不会创建新文件,若文件不存在会报错;
file=new File("name")+new FileInputStream(file)
不会创建新文件,若文件不存在也会报错;
file=new File("name")+new FileOutputStream(file),会创建新文件。
FileInputStream
public class FileInputStreamDemo {
public static void main(String[] args) throws Exception {
//1.创建流
FileInputStream inputStream = new FileInputStream("a.txt");
System.out.println("字节个数:" + inputStream.available());
//2.读取
//2.1 单个字节读取
/*int read = inputStream.read();
System.out.println(read);*/
//2.2 循环读取单个字节
/*int data;
while ((data = inputStream.read()) != -1) {
System.out.print((char) data);
}*/
//2.3 读取多个字节
byte[] buffer = new byte[5];
int len;
while ((len = inputStream.read(buffer))!=-1) {
//asdas
//d1231
//23
String str = new String(buffer,0,len);
System.out.println(str);
}
//3.关闭
inputStream.close();
}
}
对String str = new String(buffer,0,len);的理解,不加与加上范围的区别?
public String(byte bytes[]) {
this(bytes, 0, bytes.length);
}
public String(byte bytes[], int offset, int length) {
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(bytes, offset, length);
}
如果不加范围,在上次读取时如果读满了,下次读不满,没有全部覆盖数组,会把上次读的也输出。
FileOutpuStream
public class FileOutputStreamDemo {
public static void main(String[] args) throws Exception {
//1.创建文件字节输出流
//不追加 - 覆盖
//FileOutputStream stream = new FileOutputStream("a.txt");
//追加 - 不覆盖
FileOutputStream stream = new FileOutputStream("a.txt",true);
//2.写入
//2.1 写入一个字节
/*stream.write(97);
stream.write(98);
stream.write(99);*/
//2.2 写入多个字节
String s = "啊实打实啊实打实大苏打\r\n";
byte[] bytes = s.getBytes();
for (int i = 0; i < 10; i++) {
stream.write(bytes);
}
//3.关闭
stream.close();
}
}
例一:使用字节流FileInputStream处理文本文件。(可能出现乱码)
和字符流一样按四步走去操作。
@Test
public void testFileInputStream() {
FileInputStream inputStream = null;
try {
File srcFile = new File("FileReader.txt");
inputStream = new FileInputStream(srcFile);
byte[] buffer = new byte[5];
int len;
while ((len=inputStream.read(buffer))!=-1){
String str = new String(buffer,0,len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (inputStream!=null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
综合:实现对图片的复制操作。
public class CopyFile {
public static void main(String[] args) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\a.png"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\a\\bb.png"));
byte[] data = new byte[10];
while (bis.read(data) != -1) {
bos.write(data, 0, data.length);
}
bos.close();
bis.close();
System.out.println("复制成功");
}
}
4. 处理流的使用
4.1 缓冲流的使用
1.缓冲流:
没有读写文件的功能,只是增加一些功能。
BufferedInputStream、BufferedOutputStream
BufferedReader、BufferedWriter
2.作用:
- 提升了IO的读取、写入的速度,内部提供了一个缓冲区
- 数据存储在缓冲区中,flush是将缓存区的内容写入文件中,也可以直接close。
BufferedInputStream
public class BufferInputStreamDemo {
public static void main(String[] args) throws Exception{
//1.创建字节缓冲输入流
FileInputStream fis = new FileInputStream("a.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
//2.读取文件
//我们这里读了一个字节,但是缓冲区读取了8K
int data;
while ((data = bis.read()) != -1) {
System.out.print((char) data);
}
//3.关闭 只关闭缓冲流,内部把节点流关了
bis.close();
}
}
BufferedOutputStream
public class BufferOutputStreamDemo {
public static void main(String[] args) throws Exception {
//1.创建字节缓冲输出流写入文件
FileOutputStream fos = new FileOutputStream("a.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
//2.写入文件
String s = "java是世界上最好的语言\n";
byte[] bytes = s.getBytes();
for (int i = 0; i < 10; i++) {
bos.write(bytes);//8k
bos.flush();//即时刷新缓冲 (看关闭时的注意)
}
//3.关闭
//注意:关闭缓冲流,相当于关闭了底层流,会自动刷新缓冲区
bos.close();
//以上close的源码
/*public void close() throws IOException {
try (OutputStream ostream = out) {
flush();
}
}*/
}
}
代码里close源码实例演示:
class TestTry {
public static void main(String[] args) throws Exception {
//补充 try的特殊用法:自动调用close方法,对象必须实现一个接口
try (Student student = new Student()) {
System.out.println(student.toString());
//student.close(); 可以不用写
}
}
}
//要实现Closeable接口
class Student implements Closeable {
@Override
public void close() throws IOException {
}
}
- 支持输入换行符
- 可一次写一行,读一行
BufferedWriter
class BufferWriterDemo{
public static void main(String[] args) throws Exception {
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
//10.写入
for (int i = 0; i < 10; i++) {
bw.write("阿三大苏打实打实");
bw.newLine();
//bw.flush();
}
bw.close();
}
}
BufferedReader
public class BufferReaderDemo {
public static void main(String[] args) throws Exception {
//读取
//(1) 创建流
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
//(2) 读取
String line;
while ((line = br.readLine())!=null){
System.out.println(line);
}
/*String s = br.readLine();
System.out.println(s);*/
//(3) 关闭
br.close();
}
}
案例:实现非文本文件的复制
@Test
public void BufferedStreamTest(){
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.造文件
File srcFile = new File("a.jpg");
File desFile = new File("a3.jpg");
//2.造流
//2.1造节点流
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(desFile);
//2.2造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.复制的细节:读取、入
byte[] buffer = new byte[10];
int len;
while ((len = bis.read(buffer))!=-1 ){
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源关闭
//要求:先关闭外层的流,再关闭内层的流
//说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
if (bos!=null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis!=null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*fos.close();
fis.close();*/
}
4.2 转换流的使用
1.转换流: 属于字符流
InputStreamReader 将一个字节的输入流转换为字符的输入流
OutputStreamWriter 将一个字符的输出流转换为字节的输出流
2.作用:提供字节流与字符流之间的转换
解码:字节、字节数组--->字符数组、字符串
编码:字符数组、字符串--->字节、字节数组
InputStreamReader
public class InputStreamReaderDemo {
public static void main(String[] args) throws Exception {
//1.创建一个转换流
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"UTF-8");
//2.读取
char[] buf = new char[5];
int len;
while ((len = isr.read(buf)) != -1) {
String s = new String(buf, 0, len);
System.out.println(s);
}
//3.关闭
isr.close();
}
}
OutputStreamWriter
public class OutputStreamReaderDemo {
public static void main(String[] args) throws Exception {
//1.创建转换流 字符—-》字节
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("a.txt")
);
//2.写出
for (int i = 0; i < 10; i++) {
osw.write("北京\n");
}
//3.关闭
osw.close();
}
}
综合:使用InputStreamReader和OutputStreamWriter
@Test
public void test2() throws IOException {
File file1 = new File("FileReader.txt");
File file2 = new File("FileReader2.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
InputStreamReader isr = new InputStreamReader(fis);
OutputStreamWriter osw = new OutputStreamWriter(fos);
//读写过程
char[] cbuf = new char[20];
int len;
while ((len = isr.read(cbuf)) != -1) {
osw.write(cbuf, 0, len);
}
isr.close();
osw.close();
}
5. 其他流的使用
5.1 打印流
内存打印到硬盘,只有输出。
- PrintStream\PrintWriter:
- 封装了print() / println()方法,支持写入后换行。
- System.out
- PrintStream类型
- 默认打印到控制台
- 重定向标准输出流
- System.in
- FileInputStream
PrintStream/PrintWriter
public class PrintStreamDemo {
public static void main(String[] args) throws Exception{
//1创建
//字节流打印流
//PrintStream ps=new PrintStream("a.txt");
//字符流打印流
PrintWriter ps=new PrintWriter("a.txt");
//2打印
ps.println(97);
ps.println("hello");
ps.println(true);
ps.println(3.14);
ps.println('a');
//3关闭
ps.close();
System.out.println("执行完毕");
}
}
System.out
public class SystemDemo {
public static void main(String[] args) throws Exception{
System.out.println("hello");//打印到控制台
//重定向标准输出流
System.setOut(new PrintStream("d:\\console.txt"));
System.out.println(97);
System.out.println(3.14);
System.out.println(true);
System.out.println("================");
}
}
System.in
public class SystemDemo2 {
public static void main(String[] args) throws Exception{
//(1)System.in读取一个字节
// int data= System.in.read();//读取一个字节
// System.out.println((char)data);
//(2)System.in读取一个字符
// InputStreamReader isr=new InputStreamReader(System.in);
// int data=isr.read();//读取一个字符
// System.out.println((char)data);
//(3)System.in读取一行字符
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
String line=br.readLine();
System.out.println(line);
Scanner input=new Scanner(System.in);
input.nextInt();
input.next();
input.nextDouble();
}
}
5.2 RandomAccessFile
可以读取文件内容,也可以向文件中写入内容。
但是和其他输入输出流不同的是,程序可以直接跳到文件的任意位置来读写数据。
读写模式:
- r :只读
- rw : 读写
作用:
- 快速定位数据,支持并发读写
- 方便操作二进制文件
public class RandomAccessFileDemo {
public static void main(String[] args) throws Exception {
read();
}
public static void write() throws Exception {
//1.创建RandomAccessFile对象
RandomAccessFile rw = new RandomAccessFile("a.txt", "rw");
//2.写入
rw.writeUTF("liu");
rw.writeInt(20);
rw.writeBoolean(true);
rw.writeDouble(123.2);
rw.writeUTF("zhi");
rw.writeInt(20);
rw.writeBoolean(true);
rw.writeDouble(123.3);
//3.关闭
rw.close();
System.out.println("写入完毕");
}
public static void read() throws Exception {
//1.创建RandomAccessFile对象
RandomAccessFile rw = new RandomAccessFile("a.txt", "r");
//2.读取
//设置读取的指针位置 从0开始
//rw.seek(2);
//跳过指定的字节个数 从当前位置开始
//rw.skipBytes(3);
String s = rw.readUTF();
int i = rw.readInt();
boolean b = rw.readBoolean();
double aDouble = rw.readDouble();
System.out.println(s + " " + i + " " + b + " " + aDouble);
//3.关闭
rw.close();
}
}
案例多线程实现下载
public class RandomAccessFileDemo2 {
public static void main(String[] args) throws Exception{
ExecutorService es = Executors.newFixedThreadPool(4);
byte[] data=new byte[1024*1024];//1M
CountDownLatch countDownLatch=new CountDownLatch(4);
long start=System.currentTimeMillis();
for(int i=0;i<4;i++){
int n=i;
es.submit(new Runnable() {
@Override
public void run() {
RandomAccessFile raf= null;
try {
raf = new RandomAccessFile("d:\\电影.mp4", "rw");
System.out.println(Thread.currentThread().getName()+"开始下载了...");
raf.seek(n*(1024*1024));
raf.write(data);
Thread.sleep(2000);
raf.close();
System.out.println(Thread.currentThread().getName()+"下载完毕了...");
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
});
};
es.shutdown();
countDownLatch.await();
long end=System.currentTimeMillis();
System.out.println("总用时:"+(end-start));
}
}
5.3 Properties集合
Properties:属性集合
特点:
- 存储属性名和属性值
- 属性名和属性值都是字符串类型
- 没有泛型
- 和流有关
public class PropertiesDemo {
public static void main(String[] args) throws Exception {
//1创建集合
Properties properties=new Properties();
//2添加数据
properties.setProperty("name", "张三");
properties.setProperty("age","20" );
properties.setProperty("address", "北京");
//3与流有关的方法
//-------1 list 使用打印流打印数据--------
properties.list(System.out);
//-------2 store 存储到硬盘---------------
FileOutputStream fos=new FileOutputStream("d:\\user.properties");
properties.store(fos,"注释");
fos.close();
//-------3 load 加载属性文件---------
System.out.println("------load-----");
Properties properties2=new Properties();
FileInputStream fis=new FileInputStream("d:\\user.properties");
properties2.load(fis);
fis.close();
properties2.list(System.out);
}
}
6. 对象流的使用
1.objectInputStream和objectOutputStream
2.作用:
- 用于存储和读取基本数据类型数据或对象的处理流。
- 把Java中的对象写入到数据源中,也能把对象从数据源中还原回来
- 增强缓冲区的功能
3.要想一个java对象是可序列化的,需要满足相应的要求。见Person. java
4.概念:
- 序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去,使用ObjectOutputstream实现。
- 反序列化:将磁盘文件中的对象还原为内存中的一java对象,使用ObjectInputStreand
objectOutputStream
public class ObjectOutputStreamDemo {
/* public static void main(String[] args) throws Exception {
//实现序列化功能,把对象写入硬盘或网络的过程
Student student = new Student("liu",22);
//1.创建对象流
FileOutputStream fos = new FileOutputStream("a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
//2.序列化
oos.writeObject(student);
//3.关闭
oos.close();
}*/
public static void main(String[] args) throws Exception {
//实现序列化功能,把对象写入硬盘或网络的过程
Student student = new Student("liu", 22);
Student student2 = new Student("liu", 22);
Student student3 = new Student("liu", 22);
final ArrayList<Student> students = new ArrayList<>();
students.add(student);
students.add(student2);
students.add(student3);
//1.创建对象流
FileOutputStream fos = new FileOutputStream("a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
//2.序列化
oos.writeObject(students);
//3.关闭
oos.close();
}
}
class Student implements Serializable {
private static final long serialVersionUID = -4742896679480581118L;
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
改了文件的后缀,里面的内容没有改,只是用什么软件打开
objectInputStream
public class ObjectInputStreamDemo {
/* public static void main(String[] args) throws Exception {
//实现反序列化功能,把硬盘或网络的二进制文件读取到内存
//1.创建流
FileInputStream fis = new FileInputStream("a.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
//2.反序列化
Student student = (Student) ois.readObject();
System.out.println(student.toString());
//3.关闭
ois.close();
}*/
public static void main(String[] args) throws Exception {
//实现反序列化功能,把硬盘或网络的二进制文件读取到内存
//1.创建流
FileInputStream fis = new FileInputStream("a.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
//2.反序列化
ArrayList students = (ArrayList) ois.readObject();
System.out.println(students.toString());
//3.关闭
ois.close();
}
}
Person类
Person需要满足如下的要求,方可序列化:
- 1.需要实现接口: Serializable
- 2.当前类提供一个全局常量:seriaLVersionUID
- 3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)
- ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
public class Person implements Serializable {
public static final long serialVersionUID = 475463534532L;
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
对象流测试
public class ObjectInputOutputStreamTest {
/*
序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
使用ObjectOutputstream实现
*/
@Test
public void testObjectOutputStream(){
ObjectOutputStream oss = null;
try {
//1.造文件 造流
oss = new ObjectOutputStream(new FileOutputStream("object.dat"));
//2.写出
oss.writeObject(new String("我爱读书"));
oss.flush();//刷新操作
oss.writeObject(new Person("刘志",123));
oss.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
try {
oss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
反序列化:将磁盘文件中的对象还原为内存中的一java对象
使用ObjectInputStreand
*/
@Test
public void testObjectInputStream(){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object obj = ois.readObject();
String str = (String)obj;
Person p = (Person)ois.readObject();
System.out.println(str);
System.out.println(p);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
对象流说明与扩展
说明:
- 1.序列化多个对象时:集合放对象 - 见两个代码
- 2.序列化类及其对象属性必须实现Serializable接口
- 3.transient修改为瞬间(临时)属性,static属性不能序列化
- 4.读取到文件尾部的标志:java.io.EOFException
- 5.使用serialVersionUID属性保证序列化的类和反序列化的类是同一个类。
- 不带,会自动生成
扩展:
其他的接口实现序列化:
- 自动序列化接口:Serializable
- 手动序列化接口:Externalizable、 - 见代码
- 必须实现里面的方法
- 需要无参构造器
transient的属性一定不能序列化吗?
- Serializable 不能
- Externalizable 能
public class Exter_Demo {
public static void main(String[] args) throws Exception {
//实现序列化功能,把对象写入硬盘或网络的过程
Student2 student = new Student2("liu", 22);
//1.创建对象流
FileOutputStream fos = new FileOutputStream("b.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
//2.序列化
oos.writeObject(student);
//3.关闭
oos.close();
}
}
class Student2 implements Externalizable {
private String name;
private transient int age;
public Student2(String name, int age) {
this.name = name;
this.age = age;
}
public Student2() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(name);
out.writeInt(age);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = in.readUTF();
age = in.readInt();
}
}
public class ExternalizableDemo {
public static void main(String[] args) throws Exception {
//实现反序列化功能,把硬盘或网络的二进制文件读取到内存
//1.创建流
FileInputStream fis = new FileInputStream("b.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
//2.反序列化
Student2 student = (Student2) ois.readObject();
System.out.println(student.toString());
//3.关闭
ois.close();
}
}
7.内存流
ByteArrayInputStream / ByteArrayOutputSteam
- 操作的数据来自内存,流可以不用关闭。
public class ByteArrayInputStreamDemo {
public static void main(String[] args) throws Exception {
//1.创建内存流
byte[] bytes = "hellworld".getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
//2.读取
int data;
while ((data = bais.read()) != -1) {
System.out.print((char) data);
}
//3.关闭
bais.close();
}
}
public class ByteArrayOutputStreamDemo {
public static void main(String[] args) throws Exception {
//创建内存输出流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//写入到缓存数组中
byte[] data = "java是世界上最好的语言".getBytes();
baos.write(data);
//关闭
baos.close();
//获取数据
byte[] byteArray = baos.toByteArray();
String s = new String(byteArray);
System.out.println(s);
}
}
微软记事本
记事本编码转换文件,文件的大小改变,原因? BOM头 字节序的标记 Byte Order Mark
UniCode编码、Utf-8、GBK
大端、小端:
- 数字小的在后面 : 小端
- 数字大的在后面 : 大端
联通问题
GBK一个中文两个字节,但是再打开乱码。编码规则符合utf-8的规则。再另存为UTF-8时显示正常。UTF-8一个中文三个字节。
[/wppay]