IO流
File
File
类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)File
类声明在java.io
包下File
类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。
如果需要读取或写入文件内容,必须使用IO流来完成。
//new File("hi.txt")构造器,硬盘上并没有创建hi.txt,只是在内存中操作的
File file = new File("hi.txt"); //相对路径,idea中相对于当前工程
System.out.println(file.getAbsoluteFile()); // E:\CodeMgr\GitWorkplace\Java\hi.txt
try {
boolean newFile = file.createNewFile(); //这句才是在磁盘中创建文件
} catch (IOException e) {
e.printStackTrace();
}
Files
- 静态的
Files.1ist
方法会返回一个可以读取目录中各个项的stream<Path>
对象
public static void test2(){
File file = new File("E:\\homework\\大四实训");
Path path = file.toPath();
try {
Stream<Path> list = Files.list(path);
list.map(m -> m).forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
/**result:
E:\homework\大四实训\大四实训
E:\homework\大四实训\大四实训2
*/
1ist
方法不会进入子目录。为了处理目录中的所有子目录,需要使用File.walk
方法。
public static void test2(){
File file = new File("E:\\homework\\大四实训");
Path path = file.toPath();
try {
Stream<Path> walk = Files.walk(path, FileVisitOption.FOLLOW_LINKS);
walk.map(m -> m).forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
/**result
E:\homework\大四实训
E:\homework\大四实训\大四实训
E:\homework\大四实训\大四实训\1234 abv 实训报告.doc
E:\homework\大四实训\大四实训\1234abv .pptx
E:\homework\大四实训\大四实训\java提升用到的工具软件
....
....
*/
流分类
注解:我们是站在程序(内存)的角度来 区分 流的流向,流向内存的叫输入流,流向文件的叫输出流
- 按操作数据单位不同分为:字节流(8bit),字符流(16bit)
- 按数据流的流向不同分为:输入流,输出流
- 按流的角色不同分为:节点流(文件流,它是直接操作文件的流),处理流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | outputstream | Writer |
FileReader,FileWriter
- 访问文件的字符流
读取流 - a:实例化File对象,指明操作的文件
- b:建立流
- c:读取【or写入】数据
- d:关闭流
public static void test1() {
//1. 实例化File对象,指明操作的文件
File file = new File("hi.txt");
//2. 建立流
FileReader fs = null;
try {
fs = new FileReader(file);
//3. 读取数据 方式一
int read ;
while ((read = fs.read()) != -1){
System.out.print((char)read); //helloWorld-1
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
//4.关闭流
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void test1() {
//1. 实例化File对象,指明操作的文件
File file = new File("hi.txt");
//2. 建立流
FileReader fs = null;
try {
fs = new FileReader(file);
//3. 读取数据 方式二
int read ;
char[] cbuf = new char[5]; //这里一次放5个char字符串
/** public int read(char cbuf[]):每次把读取的数据放入数组中,这样可以减少时间
* 例如:外卖小哥送外卖,方式一相当于拿一个送走一个,方式二相当于一次拿5个,然后送走。这样省时
* 这里hi.txt文本的数据是“helloWorld147”,共13个字符,需要三趟,其中第三趟读取了3个字符
* */
while ((read = fs.read(cbuf)) != -1){
for (int i=0; i< read; i++) //若 i<cbuf.length,则输出结果:helloWorld147ld
System.out.print(cbuf[i]);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
//4.关闭流
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
写入磁盘
- 文件写入磁盘时,对应的
File
可以不存在的,并不会报异常;File对应的硬盘中的文件如果不存在,其输出的过程中,会自动创建此文件。 - File对应的硬盘中的文件如果存在:如果流使用的构造器是:
Filewriter(file,false)/Filewriter(file)
:对原有文件的覆盖;
如果流使用的构造器是:Filewriter(file,true)
不会对原有文件覆盖,而是在原来的文件基础上追加数据.
public static void test2(){
//1. 实例化File对象,指明操作的文件
File file = new File("hi.txt"); //向hi.txt文件中写入数据
FileWriter fw = null;
try {
//2. 建立流
fw = new FileWriter(file);
//3.写入
fw.write("abc");
} catch (IOException e) {
e.printStackTrace();
}finally {
//4.关闭流
try {
if (null != fw)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结论
- 不能用字符流处理图片等字节类型的数据
- 对于文本文件
(.txt,.java,.c,.cpp)
,使用字符流处理 - 对于非文本文件
(.jpg,.mp3,.mp4,.avi,.ppt.…)
,使用字节流处理
FileInputStream,Fileoutputstream
- 访问文件的字节流
例如
//实现图片的复制
public static void test3(){
FileInputStream fis = null;
FileOutputStream fos = null;
//1.创建文件
File file1 = new File("图片.jpg");
File file2 = new File("图片复制.jpg");
try {
//2.构造流
fis = new FileInputStream(file1);
fos = new FileOutputStream(file2);
//3.读取or写入
int len;
byte[] buf = new byte[5];
while ((len = fis.read(buf)) != -1){
fos.write(buf,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//4.关闭流
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null){
try {
fos.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
BufferedInputStream,BufferedOutputStream
- 操作字节的缓存流(处理流)
例如
/**
* 读取一幅图片并写入磁盘
* idea中Ctrl+Alt+T,可以把代码包在一个块内,例如:try/catch
* */
public static void test4() {
BufferedInputStream bis= null;
BufferedOutputStream bos = null;
try {
//1.创建文件
File file1 = new File("图片.jpg");
File file2 = new File("图片复制1.jpg");
//2.创建流
//2.1创建字节流
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
//2.2创建缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.读取并写入
byte[] buffer = new byte[5];
int len;
while ((len = bis.read(buffer)) !=-1){
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流
/**
* 要求:先关闭外层的流,后关闭内层的流
* 关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,可以省略。
* */
try {
if (bos != null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bis!= null)
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedReader,BufferedWriter
- 操作字符的缓冲流(处理流)
例如
/**
* 文本文件的复制
* */
public static void test5(){
BufferedReader br = null;
BufferedWriter bw = null;
try {
//创建文件,创建流
br = new BufferedReader(new FileReader(new File("hi.txt")));
bw = new BufferedWriter(new FileWriter(new File("hi复制.txt")));
//读取 写入
int len;
char[] cbuf = new char[1024];
while ((len = br.read(cbuf)) != -1){
bw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
InputStreamReader,OutputStreamWriter
-
转换流(字符流)
-
InputStreamReader:将一个字节的输入流转换为字符的输入流
-
OutputStreamwriter:将一个字符的输出流转换为字节的输出流
标准输入输出流
- System.in:标准的输入流,默认从键盘输入
- System.out:标准的输出流,默认从控制台输出
例子
/**
* 此处用到:标准输入流,标准输出流,转换流.
* 例:从控制台输入字符串,将其转换为大写的字符串
* */
public static void test6(){
BufferedReader br = null; //读取字符流
try {
InputStream in = System.in; //从控制台接收数据
InputStreamReader isr = new InputStreamReader(in);//用 转换输入流 将字节流转换为字符流
br = new BufferedReader(isr);
while (true){
System.out.print("输入字符串: ");
String s = br.readLine();
if (s.equalsIgnoreCase("e")
|| s.equalsIgnoreCase("exit")){
System.out.println("终止");
break;
}
System.out.println(s.toUpperCase());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close(); //只用关闭外层流即可
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
对象流
序列化:
- 用
ObjectOutputStream
类保存基本类型数据或对象的机制
反序列化 - 用
ObjectlnputStream
类读取基本类型数据或对象的机制
序列化的例子
/**
序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
该操作将hello,世界,写入到obj.data数据文件中,obj.data被持久化到磁盘中
* */
public static void test7(){
ObjectOutputStream oos = null;
try {
//1.操作文件
oos = new ObjectOutputStream(new FileOutputStream("obj.data"));
//2.写入
oos.writeObject(new String("hello,世界"));
oos.flush();//刷新操作
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关闭
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
反序列化例子
/**
反序列化:将磁盘文件中的对象还原为内存中的一个java对象
该操作将hello,世界,从obj.data文件中读取出来
* */
public static void test8(){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("obj.data"));
Object o = ois.readObject();
String s = (String) o;
System.out.println(s);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
总结:
ObjectOutputStream
和ObjectlnputStream
不能序列化static
和transient
修饰的成员变量- 对象要想序列化需要满足的要求:
①需要实现接口:Serializable
②当前类提供一个全局常量:serialVersionUID
③除了当前类需要实现Serializable
接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)
//反序列化一个类
public static void test10(){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("obj.data"));
String s1 = (String) ois.readObject(); //读取顺序按照写入顺序读取
System.out.println(s1);//你好
Person person = (Person) ois.readObject();
System.out.println(person);//Person{name='abc', age=22}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//序列化一个类
public static void test9(){
ObjectOutputStream oos = null;
try {
//1.操作文件
oos = new ObjectOutputStream(new FileOutputStream("obj.data"));
//2.写入
oos.writeObject(new String("你好"));
oos.flush();
oos.writeObject(new Person("abc",22));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关闭
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//person类需要序列化
class Person implements Serializable{
private static final long serialVersionUID = -6849794470754667710L;
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 +
'}';
}
}
//若是将Person类中成员变量加以static和transient修饰,则反序列化输出的结果如下:
String s1 = (String) ois.readObject(); //读取顺序按照写入顺序读取
System.out.println(s1); //你好
Person person = (Person) ois.readObject();
System.out.println(person); //Person{name='null', age=0}
RandomAccessFile
RandomAccessFile
直接继承java.Lang.Object
类,实现了DataInput
和Dataoutput
接口RandomAccessFile
既可以作为一个输入流,又可以作为一个输出流RandomAccessFile
作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建,如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
该类有个方法seek()
,用于定位指针位置。
IO流和网络
- 在Java中使用
InetAddress
类代表IP - 端口号
①端口号标识正在计算机上运行的进程(程序)
②不同的进程有不同的端口号,被规定为一个16位的整数0~65535。 - 端口分类:
①公认端口:0~1023。被预先定义的服务通信占用(如:HTTP占用端口80,FTP占用端口21,Telnet占用端口23)
②注册端口:1024~49151。分配给用户进程或应用程序。(如:Tomcat占用端口8080,MySQL占用端口3306,Oracle占用端口1521等)
③动态/私有端口:49152~65535
端口号与IP地址的组合得出一个网络套接字:Socket
简单例子
//客户端
public static void test11() {
Socket socket = null;
OutputStream os = null;
try {
//1.实例化Socket对象,指定服务器端 IP和端口号
socket = new Socket(InetAddress.getByName("127.0.0.1"), 8888);
//2.获取一个输出流,用于发送数据
os = socket.getOutputStream();
//3.写出数据
os.write("I am 客服端".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//服务器端
public static void test12() throws IOException {
//1.实例化ServerSocket,指明自己的端口号
ServerSocket ss = new ServerSocket(8888);
//2.接收来自客户端Socket
Socket socket = ss.accept();
//3.获取输入流
InputStream is = socket.getInputStream();
//4.读数据
//ByteArrayOutputStream属于字节流,若不用ByteArrayOutputStream,直接用new byte[5]数组,
//当放入中文(占3个字节)第二个中文会出现乱码(每放入5个字节,就被覆盖了,直接放入下5个字节),
//而ByteArrayOutputStream内部是byte buf[]数组,构造器创建时,默认构造32大小容量,当缩放字
//节数超过32,会自动扩容(这里扩容2倍),其前面32字节不会被覆盖(相当于追加)。
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
byte[] bytes = new byte[5];
while ((len = is.read(bytes)) != -1){
baos.write(bytes,0,len);
}
System.out.println(baos.toString());
//4.关闭流
baos.close();
is.close();
socket.close();
ss.close();
}
URL编程
URL(Uniform Resource Locator):
统一资源定位符,它表示Internet
上某一资源的地址。URL
的基本结构由5部分组成: <传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表
例如:http://192.168.1.100:8080/helloworld/index.jsp#a?username=abc&password=123