Java学习之IO流及网络编程

一、字节

1.1字节输入流(java.io.InputStream)

​ 此抽象类是表示字节输入流的所有类的超类

1.1.1定义了所有子类共性的方法:

​ int read() 从输入流中读取数据的下一个字节

​ int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中。

​ void close() 关闭此输入流并释放与流关联的所有系统资源。

java.io.FileInputStream extends InputStream

1.1.2FileInputStream: 文件字节输入流

作用:把硬盘文件中的数据,读取到内存中使用

​ 构造方法:

​ FileInputStream(String name)

​ FileInputStream(File file)

​ 参数:读取文件的数据源

​ String name:文件的路径

​ File file:文件

​ 构造方法的作用:

​ 1.会创建一个FileInputStream对象

​ 2.会把FileInputStream对象指定的构造方法中要读取的文件

1.1.3读取数据的原理(硬盘 --> 内存)

​ java程序 --> JVM -->OS -->OS读取数据的方法 --> 读取文件

1.1.4字节输入流的使用步骤:(重点)

​ 1.创建FileInputStream对象,构造方法中绑定要读取的数据源

​ 2.使用FileInputStream对象的方法read,读取文件

​ 3.释放资源

1.1.5字节输入流一次读取多个字节方法

int read(byte[] b) 从输入流中读取一定数量的姐,并将其存储在缓冲区数组b中。

明确两件事情:

​ 1.方法的参数byte[]的作用?

​ 起到缓冲作用,存储每次读取到的多个字节

​ 数组的长度一把定义为1024(1kb)或者1024的整数倍

​ 2.方法的返回值int是什么?

​ 每次读取的有效字节个数

String类的构造方法:

​ String(byte[] bytes):把字节数组转换为字符串

​ String(byte[] bytes, int offset , int length) 把字节数组的一部分转换为字符串 offset:数组的开始索引 length:转换的字节个数

1.2字节输出流(java.io.OutputStream)

​ 此抽象类是表示输出字节流的所有类的超类

1.2.1子类共性的成员方法

​ public void close() :关闭此输出流并释放与此流相关联的任何系统资源。

​ public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出

​ public void write(byte[] b) :将 b.length字节从指定的字节数组写入此输出流。

​ public void write(byte[] b, int off , int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。

​ public abstract void write(int b): 将指定的字节输出流

java.io.FileoutputStream extends OutputStream

1.2.2 FileOutputStream:文件字节输出流

​ 作用:把内存中的数据写入到硬盘的文件中

1.2.3构造方法

​ FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流

​ FileOutputStream(File file) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流

参数:

​ String name:目的地是一个文件的路径

​ File file:目的地是一个文件

构造方法的作用:

​ 1.创建一个FileOutputStream对象

​ 2.会根据构造方法中传递的文件/文件路径,创建一个空的文件

​ 3.会把FileOutputStream对象指向创建好的文件

1.2.4写入数据的原理(内存 --> 硬盘)

​ java程序 --> JVM(java虚拟机)--> OS(操作系统)--> OS调用写数据的方法 --> 把数据写入到文件中

1.2.5字节输出流的使用步骤(重点):

​ 1.创建一个FileOutputStream对象,构造方法中传递写入数据的目的地

​ 2.调用FileOutputStream对象中的方法write,把数据写入到文件中

​ 3.释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序的效率)

二、字符

2.1字符输入流(java.io.Reader)

​ 字符输入流,是字符输入流的最顶层的父类,定义了一些共性的成员方法,是一个抽象类。

2.1.1共性的成员方法:

​ int read() 读取单个字符并返回。

​ int read(char[] cbuf) 一次读取多个字符,将字符读入数组。

​ void close() 关闭该流并释放与之关联的所有资源。

java.io.FileReader extends InputStreamReader extends Reader

2.1.2 FileReader:文件字符输入流

​ 作用:把硬盘文件中的数据以字符的方式读取到内存中

2.1.3构造方法

​ FileReader(String fileName)

​ FileReader(File file)

​ 参数:读取文件的数据源

​ String fileName:文件的路径

​ File file:一个文件

​ FileReader构造方法的作用:

​ 1.创建一个FileReader对象

​ 2.会把FileReader对象指向要读的文件

2.2字符输出流(java.io.Writer)

​ 字符输出流,是所有字符输出流的最顶层的父类,是一个抽象类

2.2.1共性的成员方法:

​ void write(int c) 写入单个字符

​ void write(char[] cbuf) 写入字符数组

​ abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分,off数组的开始索引,len写的字符个数。

​ void write(String str) 写入字符串

​ void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。

​ void flush() 刷新该流的缓冲

​ void close() 关闭此流,但要先刷新它。

java.io.FileWriter extends OutputStreamWriter extends Writer

2.2.2 FileWriter:文字字符输出流

​ 作用:把内存中字符数据写入到文件中

2.2.3构造方法

​ FileWrter(File file) 根据给定的File 对象构造一个 FileWriter 对象。

​ FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象。

参数:写入数据的目的地

​ String fileName:文件的路径

​ File file:是一个文件

构造方法的作用:

​ 1.会创建一个FileWriter对象

​ 2.会根据构造方法中传递的文件/文件的路径,创建文件、

​ 3.会把FileWriter对象指向创建好的文件

2.3文件字符输出流(FileWriter)

​ 作用:把内存中字符数据写入到文件中

2.3.1构造方法

​ FileWriter(File file) 根据给定的File 对象构造一个 FileWriter 对象。

​ FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象。

参数:写入数据的目的地

​ File file:是一个文件

​ String fileName:文件的路径

构造方法的作用:

​ 1.会创建一个FileWriter对象

​ 2.会根据构造方法中传递的文件/文件的路径,创建文件

​ 3.会把FileWriter对象指向创建好的文件

2.3.2字符输出流的使用步骤(重点):

​ 1.创建FileWriter 对象,构造方法中绑定要写入数据的目的地

​ 2.使用FileWriter 中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)

​ 3.使用FileWriter中的方法flush,把内存缓冲区中的数据,刷新到文件中

​ 4.释放资源(会先把内存缓冲区中的数据刷新到文件中)

三、Properties集合

3.1 使用Properties集合存储数据,遍历取出数据

​ Properties集合是一个双列集合,key和value默认都是字符串

​ Properties集合有一些操作字符串的特有方法:

​ Object setProperty(String key, String value) 调用Hashtable 的方法 put

​ String getProperty(String key) 通过key找到value值,此方法相当于Map集合中的get(key)方法。

​ Set stringPropertyNames() 返回此属性列表中的值,其中该键机器对应值是字符串,此方法相当于Map集合中的keyset方法

package DemoIO;

import java.util.Properties;
import java.util.Set;

public class Demo01Properties {
    public static void main(String[] args) {
        show01();
    }

    private static void show01() {
//        创建Properties集合
        Properties prop = new Properties();
//        使用serProperty往集合中添加数据
        prop.setProperty("赵丽颖","168");
        prop.setProperty("迪丽热巴","165");
        prop.setProperty("古力娜扎","163");
//        使用stringPropertyName把Properties集合中的键取出,存储到一个set集合中
        Set<String> set = prop.stringPropertyNames();
//        遍历set集合,取出Properties集合中的每一个键
        for (String s : set) {
            System.out.println("名字:"+s+",年龄:"+prop.getProperty(s));
            /*
            *名字:赵丽颖,年龄:168
             名字:古力娜扎,年龄:163
             名字:迪丽热巴,年龄:165
            * */
        }
    }
}

3.2 store方法

​ Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储。

​ void store(OutputStream out , String comments)

​ void store(Writer writer , String comments)

参数:

​ OutputStream out :字节输出流,不能写入中文

​ Writer writer :字符输出流,可以写中文

​ String comments: 注释 ,用来解释说明保存的文件是做什么用的

​ 不能使用中文,会产生乱码,默认是Unicode编码

​ 一般使用“ ” 空字符串

3.2.1使用步骤

​ 1.创建Properties集合对象,添加数据

​ 2.创建字节输出流/字输出流对象,构造方法中绑定要输出的目的地

​ 3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘存储

​ 4.释放资源

3.3 load方法

​ 作用:把硬盘中保存的文件(键值对),读取到集合中使用。

​ void load(InputStream inStream)

​ void load(Reader reader)

​ 参数:

​ InputStream inStream:字节输入流,不能读取含有中文的键值对

​ Reader reader:字符输入流,能读取含有中文的键值对

3.3.1使用步骤

​ 1.创建Properties集合对象

​ 2.使用Properties集对象中的方法load读取保存键值对的文件

​ 3.遍历Properties集合

【注意】:

​ 1.存储键值对的文件中,键与值默认的连接符号可以用=,空格(其他符号)

​ 2.存储键值对的文件中,可以使用#进行注释,备注是的键值对不会再被读取

​ 3.存储键值对的文件中,键与值默认都是字符串,不用再加引号

四、缓冲流

java.io.BufferedOutputStream extends OutputStream

4.1 字节缓冲输出流:

BufferedOutputStream

继承自父类的共性方法:(字节输出流的共性方法)

4.1.1 构造方法:

​ BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

​ BufferedOutputStream(OutputStream out,int size) 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流

参数:

​ OutputStream out:字节输出流

​ 我们可以传递FileOutputStream,缓冲流会给FileOutputStream增加一个缓冲区,提高FileOutputStream的写入效率

​ int size:指定缓冲流内部缓冲区的大小,不指定默认。

4.1.2使用步骤:(重点)

​ 1.创建FileOutputStream对象,构造方法中绑定要输出的目的地

​ 2.创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象效率。

​ 3.使用BufferedOutputStream对象中的方法write,把数据西而入到内部缓冲区中

​ 4.使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中

​ 5.释放资源(会先调用flush方法刷新数据,第4步可以省略)

4.2字节缓冲输入流

java.io.BufferedInputStream extends InputStream
bufferedInputStream:字节缓冲输入流

4.2.1 继承自父类的成员方法:

​ int read() 从输入流中读取数据的下一个字节。
​ int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
​ void close() 关闭此输入流并释放与该流关联的所有系统资源。

4.2.2构造方法:

​ BufferedInputStream(InputStream in) 创建一个BufferedInputStream 并保存其参数 , 即输入流 in,以便将来使用
​ BufferedInputStream(InPutStream in,int size) 创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流

参数:
InputStream in:字节输入流
我们可以传递 FileInputStream,缓冲流会给FileInputStream对象,提高FileInputStream的读取效率
int szie:指定缓冲流内部缓冲区的大小,不指定默认

使用步骤(重点):
1.创建FileInputStream对象,构造方法中绑定要读取的数据流
2.创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
3.使用BufferedInputStream对象中的方法read,读取文件

​ 4.释放资源

4.3字符缓冲输出流

java.io.BufferedWriter extends Writer
BufferedWriter:字符缓冲输出流

4.3.1继承自父类的共性成员方法: Writer

4.3.2构造方法:

​ BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流
​ BufferedWriter(Writer out,int sz) 创建一个使用给定大小输出缓冲区的缓冲字符输出流
参数:
​ Writer out:字符输出流
​ 我们可以传递 FileWriter,缓冲流给FileWriter 增加一个缓冲区,提高FileWriter的写入效率
​ int sz:指定缓冲区的大小,不写默认大小

4.3.3特有的成员方法:

​ void newLine() 写入一个行分隔符。会根据不同的操作系统,获取不同的行分隔符
​ 换行:换行符号
​ windows:\r\n
​ linux:/n
​ mac:/r

4.3.4使用步骤:

​ 1.创建字符缓冲输出流对象,构造方法中传递字符输出流
​ 2.调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区中
​ 3.调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据,刷新到文件中
​ 4.释放资源

4.4字符缓冲输入流

java.io.BufferedReader extends Reader

4.4.1继承自父类的共性的成员方法:Reader类

4.4.2构造方法:

​ BufferedReader(Reader in) 创建一个使用默认大小缓冲输入缓冲区的缓冲字符输入流
​ BufferedReader(Reader in,int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流
参数:
​ Reader in:字符输入流
​ 我们可以传递FileReader,缓冲流会给FileReader增加一个缓冲区,提高FileReader的读取效率

4.4.3特有的成员方法:

​ String readLine() 读取一个文本行。读取一行数据
​ 行的终止符号:通过下列字符之一即可认为某行已终止:换行('\n')、回车('\r')或回车直接跟着换行(\r\n)
​ 返回值:
​ 包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null

4.4.4使用步骤:

​ 1.创建字符缓冲输入流对象,构造方法中传递字符输入流
​ 2.使用字符缓冲输入流对象的方法read/readLine读取文本
​ 3.释放资源

五、序列化与反序列化

5.1序列化的概念:

把对象以流的方式,写入到文件中保存,叫写对象,也叫对象的序列化

5.1.1 java.io.ObjectOutputStream extends OutputStream

ObjectOutputStream:对象的序列化流
作用:把对象以流的方式写入到文件中保存

5.1.2构造方法:

​ ObjectOutputStream(OutputStream out) 创建写入指定OutputStream 的ObjectOutputStream
参数:
​ OutputStream out:字节输出流

5.1.3特有的成员方法:

​ void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream

5.1.4使用步骤:

​ 1.创建ObjectOutputStream对象,构造方法中传递字节输出流
​ 2.使用ObjectOutputStream对象的方法writeObject,把对象写入到文件中
​ 3.释放资源

5.2反序列化的概念:

把文件中保存的对象,以流的方式读取出来,叫做读对象,也叫对象的反序列化

5.2.1java.io.ObjectInputStream extends InputStream

ObjectInputStream:对象的反序列化流
作用:把文件中保存的对象,以流的方式读取出来使用

5.2.2构造方法:

​ ObjectInputStream(InputStream in) 创建从指定 InputStream 读取的ObjectInputStream
参数:
​ InputStream in:字节输入流

5.2.3特有的成员方法:

​ Object readObject() 从 ObjectInputStream 读取对象

5.2.4使用步骤:

​ 1.创建 objectInputStream对象,构造方法中传递字节输入流
​ 2.使用objectInputStream对象中的方法readObject读取保存对象的文件
​ 3.释放资源
​ 4.使用读取出来的对象(打印)

5.3 NotSerizalizableException:没有序列异常

引出:序列化和反序列化的时候,会抛出NotSerizalizableException没有序列化异常

​ 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法 使其任何状态序列化或反序列化

Serializable接口也叫标记型接口:

​ 要进行序列化和反序列化的类必须实现 Serializable 接口,就会给类添加一个标记

​ 当我们进行序列化和反序列化的时候,就会检测类上是否有这个标记

​ 有:就可以序列化和反序列化

​ 没有:就会抛出NotSerizalizableException 异常

例如:菜市场卖肉 --> 肉上有蓝色章(检测合格) --> 放心购买 --> 买回来怎么吃随意

六、网络编程

6.1 TCP通信的客户端

TCP的客户端:像服务器发送连接请求,给服务器发送数据,读取服务器回写的数据

6.1.1表示客户端的类

​ java.net.Socket 此类实现客户端套接字(也可以称为“套接字”)。套接字是两台机器键通信的端点。

​ 套接字:包含了IP地址和端口号的网络单位

6.1.2构造方法

​ Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。

​ 参数:

​ String host :服务器主机的名称/服务器的IP地址

​ int port :服务器的端口号

6.1.3成员方法

​ OutputStream getOutputStream() 返回此套接字的输出流

​ InputStream getInputStream 返回此套接字的输入流

​ void close() 关闭此套接字

6.1.4实现步骤

​ 1.创建一个客户端对象Socket,构造方法绑定服务器的IP地址和端口

​ 2.使用Socket对象的方法getOutputStream()获取网络字节输出流OutputStream对象

​ 3.使用网路字节输出流OutputStream对象中的方法write,给服务器发送数据

​ 4.使用Socket独享中的方法getInputStream()获取网络字节输入流InputStream对象

​ 5.使用网络字节输入流InputStream对象中的方法read,读取服务器会写的数据

​ 6.释放资源(Socket)

6.1.5注意

​ 1.客户端和服务器进行交互,必须使用Socket中提供的网络流,不能使用自己创建的流对象

​ 2.当我们创建客户端对象Socket的时候,就回去请求服务器和服务器经过3次握手建立连接通路

​ 这时如果服务器没有启动,那么就会抛出异常

​ 如果服务器已经打开,那么就可以进行交互了

6.1.6 代码

package DemoSocket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TCPClient {
    public static void main(String[] args) throws IOException {
//        1.创建一个客户端对象Socket,构造方法绑定服务器的IP地址和端口号
        Socket socket = new Socket("127.0.0.1",8888);
//        2.使用Socket对象的方法getOutputStream()获取网络字节输出流OutputStream对象
        OutputStream outputStream = socket.getOutputStream();
//        3.使用网路字节输出流OutputStream对象中的方法write,给服务器发送数据
        outputStream.write("你好服务器".getBytes());
//        4.使用Socket独享中的方法getInputStream()获取网络字节输入流InputStream对象
        InputStream inputStream = socket.getInputStream();
//        5.使用网络字节输入流InputStream对象中的方法read,读取服务器会写的数据
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        System.out.println(new String(bytes,0,len));
//        6.释放资源(Socket)
        socket.close();
    }
}

6.2 TCP通信的服务器端

TCP通信的服务器端:接收客户端的请求,读取客户端发送的数据,给客户端回写数据

6.2.1表示服务器的类

​ java.net.ServerSocket:此类实现服务器套接字。

6.2.2构造方法

​ ServerSocket(int port) 创建绑定到特定端口的服务器套接字

服务器端必须明确一件事情,必须知道是哪个客户端请求的服务器

所以可以使用accept()方法获取到请求客户端对象Socket

6.2.3成员方法

​ Socket accept() 侦听并接受到此套接字的连接。

6.2.4服务器的实现步骤

​ 1.创建服务器ServerSocket对象和系统指定的端口号

​ 2.使用ServerSocket对象中的方法accept,获取到请求的客户端对象Socket

​ 3.使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象

​ 4.使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据

​ 5.使用Socket对象的方法getOutputStream()获取网络字节输出流OutputStream对象

​ 6.使用网路字节输出流OutputStream对象中的方法write,给客户端的回写数据

​ 7.释放资源(Socket, ServerSocket)

6.2.5 代码

package DemoSocket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer {
    public static void main(String[] args) throws IOException {
//        1.创建服务器ServerSocket对象和系统指定的端口号
        ServerSocket serverSocket = new ServerSocket(8888);
//        2.使用ServerSocket对象中的方法accept,获取到请求的客户端对象Socket
        Socket socket = serverSocket.accept();
//        3.使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
        InputStream inputStream = socket.getInputStream();
//        4.使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        System.out.println(new String(bytes,0,len));
//        5.使用Socket对象的方法getOutputStream()获取网络字节输出流OutputStream对象
        OutputStream outputStream = socket.getOutputStream();
//        6.使用网路字节输出流OutputStream对象中的方法write,给客户端的回写数据
        outputStream.write("收到,谢谢".getBytes());
//        7.释放资源(Socket, ServerSocket)
        socket.close();
        serverSocket.close();
    }
}

6.3文件上传案例

原理:image-20200420171434874

6.3.1文件上传案例的客户端

读取本地文件,上传到服务器,读取服务器回写的数据

明确:

​ 数据源:e:\荷塘.jpg

​ 目的地:服务器

实现步骤:

​ 1.创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源

​ 2.创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号

​ 3.使用Socket中的方法getOutputStream,获取网络字节输出流OutputStream对象

​ 4.使用本地字节输入流FileInputStream对象中的方法read,读取本地文件

​ 5.使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器

​ 6.使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象

​ 7.使用网络字节输入流InputStream对象中的方法read读取服务器回写的数据

​ 8.释放资源(FileInputStream,Socket)

代码:

package UploadSocketDemo;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TCPClient {
    public static void main(String[] args) throws IOException {
//        1.创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源
        FileInputStream file = new FileInputStream("E:\\photos\\bizhi\\荷塘.jpg");
//        2.创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
        Socket socket = new Socket("127.0.0.1",8888);
//        3.使用Socket中的方法getOutputStream,获取网络字节输出流OutputStream对象
        OutputStream outputStream = socket.getOutputStream();
    //        4.使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
        int len = 0;
        byte[] bytes = new byte[1024];
        while((len = file.read(bytes))!=-1){
            // 5.使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
            outputStream.write(bytes,0,len);
        }
        /*
        * 解决:上传完文件,给服务器协议个结束标记
        * void shutdownOutput() 禁用此套接字的输出流
        * 对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列
        * */
        socket.shutdownOutput();
//        6.使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象
        InputStream inputStream = socket.getInputStream();

//        7.使用网络字节输入流InputStream对象中的方法read读取服务器回写的数据
        while((len = inputStream.read(bytes))!=-1){
            System.out.println(new String(bytes,0,len));
        }

//        8.释放资源(FileInputStream,Socket)
        file.close();
        socket.close();
    }
}

6.3.2文件上传案例的服务器端

读取客户端上传的文件,保存到服务器的硬盘,给客户端回写“上传成功”

明确:

​ 数据源:客户端上传的文件

​ 目的地:服务器的硬盘 d:\upload\荷塘.jpg

实现步骤:

​ 1.创建一个服务器ServerSocket对象,和系统要指定的端口号

​ 2.使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象

​ 3.使用Socket独享中的方法getInputStream,获取到网络字节输入流InputStream对象

​ 4.判断e:\upload文件夹是否存在,不存在则创建

​ 5.创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地

​ 6.使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件

​ 7.使用本地的字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上

​ 8.使用Socket独享中的方法getOutputStream,获取到网络字节输出流OutputStream对象

​ 9.使用网络字节输出流OutputStream对象中的方法write,给客户端回写“上传成功”

​ 10.释放资源(FileOutputStream,Socket,ServerSocket)

代码:

package UploadSocketDemo;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

public class TCPServer {
    public static void main(String[] args) throws IOException {
//        1.创建一个服务器ServerSocket对象,和系统要指定的端口号
        ServerSocket server = new ServerSocket(8888);
//        2.使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象
        /*
        * 让服务器一直处于监听状态(死循环accept方法)
        * 有一个客户端上传文件,就保存一个文件
        * */
        while (true) {
            Socket socket = server.accept();
//            /*
//            * 使用多线程技术,提高程序的效率
//            * 有一个客户端上传文件,就开启一个线程,完成文件的上传
//            * */
//            new Thread(new Runnable() {
////                完成文件的上传
//                @Override
//                public void run() {
//
//                }
//            }).start();

//        3.使用Socket独享中的方法getInputStream,获取到网络字节输入流InputStream对象
            InputStream inputStream = socket.getInputStream();
//        4.判断e:\\upload文件夹是否存在,不存在则创建
            File file = new File("e:\\upload");
            if (!file.exists()) {
                file.mkdir();
            }

        /*
        自定义一个文件的命名规则:防止同名的文件被覆盖
        规则:域名+毫秒值+随机数
         */
            String fileName = "king" + System.currentTimeMillis() + new Random().nextInt(99999999) + ".jpg";
//        5.创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
            FileOutputStream fileOutputStream = new FileOutputStream(file + "\\" + fileName);
//        6.使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件
            int len = 0;
            byte[] bytes = new byte[1024];
            while ((len = inputStream.read(bytes)) != -1) {
                //7.使用本地的字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
                fileOutputStream.write(bytes, 0, len);
            }
//        8.使用Socket独享中的方法getOutputStream,获取到网络字节输出流OutputStream对象
            OutputStream outputStream = socket.getOutputStream();
//        9.使用网络字节输出流OutputStream对象中的方法write,给客户端回写“上传成功”
            outputStream.write("上传成功".getBytes());
//        10.释放资源(FileOutputStream,Socket,ServerSocket)
            fileOutputStream.close();
            socket.close();
        }
//        server.close();
    }
}

猜你喜欢

转载自www.cnblogs.com/KingTL/p/12945269.html
今日推荐