Java学习与复习笔记--综合案例_文件上传

文件上传的原理:

使用客户端读取本地的文件,把文件上传到服务器,服务器再把上传的文件保存到服务器的硬盘上

1.客户端使用本地的字节输入流,读取要上传的文件

2.客户端使用网络字节输出流,把读取到的文件上传到服务器

3.服务器使用网络字节输入流,读取客户端上传的文件

4.服务器使用本地字节输出流,把读取到的文件,保存到服务器的硬盘上

5.服务器使用网络字节输出流,给客户端回写一个“上传成功”

6.客户端使用网络字节输入流,读取服务器回写的数据

7.释放资源

注意:客户端和服务器和本地硬盘进行读写,需要使用自己创建的字节流对象(本地流)

           客户端和服务器之间进行读写,必须使用Socket中提供的字节流对象(网络流)

文件上传的原理,就是文件的复制

明确:数据源,数据目的地

文件上传案例的客户端:

/*
* 文件上传案例的客户端:
*   读取本地文件,上传到服务器,读服务器回写的数据
*  明确:数据源:d:\\1.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)*/
public class TCPClient {
    public static void main(String[] args) throws IOException {
        FileInputStream fis=new FileInputStream("d:\\1.jpg");
        Socket socket=new Socket("127.0.0.1",8888);
        OutputStream os = socket.getOutputStream();
        int len=0;
        byte[] bytes=new byte[1024];
        while((len=fis.read(bytes))!=-1){
            os.write(bytes,0,len);
        }
        InputStream is = socket.getInputStream();
        while((len=is.read(bytes))!=-1){
            System.out.println(new String (bytes,0,len));
        }
        fis.close();
        socket.close();
    }
}

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

/*
* 文件上传案例的服务器端:读取客户端上传的文件,保存到服务器的硬盘,给客户端回写“上传成功”
*  明确:
*     数据源:客户端上传的文件
*     目的地:服务器的硬盘 D:\\upload\\1.jpg
*  实现步骤:
*    1.创建一个服务器ServerSocket对象,和系统要指定的端口号
*    2.使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象
*    3.使用Socket对象中的方法getInputStream,获取网络输入流InputStream对象
*    4.判断D:\\upload文件夹是否存在,不存在则创建
*    5.创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
*    6.使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件
*    7.使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
*    8.使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
*    9.使用网络字节输出流OutputStream对象中的方法,给客户端回写“上传成功”
*    10.释放资源(FileOutputStream,Socket,ServerSocket)*/
public class TCPServer {
    public static void main(String[] args) throws IOException {
        ServerSocket server=new ServerSocket(8888);
        Socket socket = server.accept();
        InputStream is = socket.getInputStream();
        File file=new File("D:\\upload");
        if(!file.exists()){
            file.mkdirs();
        }
        FileOutputStream fos=new FileOutputStream(file+"\\1.jpg");
        int len=0;
        byte[] bytes=new byte[1024];
        while((len=is.read(bytes))!=-1){
            fos.write(bytes,0,len);
        }
        socket.getOutputStream().write("上传成功".getBytes());
        fos.close();
        socket.close();
        server.close();
    }
}

文件上传案例阻塞问题:

客户端里:fis.read(bytes)读取本地文件,结束标记是读取到-1结束

while循环里不会读取-1,那么也不好把结束标记写给服务器。

服务器里:is.read()读取客户端上传的文件,永远也读取不到文件的结束标记,read方法进入到阻塞状态,一直死循环等待结束标记。

回写给客户端的信息无法上传成功。

客户端里:is.read()读取不到服务器回写的数据,进入到阻塞状态

解决:上传完文件,给服务器写一个结束标记

* void shutdownOutput() :禁用此套接字的输出流。 */ socket.shutdownOutput();

文件上传案例优化:

优化内容:

1.自定义一个文件的命名规则:防止文件名被覆盖

2.让服务器一直处于监听状态(死循环accept方法)

3.使用多线程技术,提高程序的效率

public class FileUploadServer {
    public static void main(String[] args) throws IOException {
        ServerSocket server=new ServerSocket(8888);
        /*
        * 让服务器一直处于监听状态(死循环accept方法)
        * 有一个客户端上传文件,就保存一个文件
        * */
        while(true){
            Socket socket = server.accept();
            /*
            * 使用多线程技术,提高程序的效率
            * 有一个客户端上传文件,就开启一个线程,完成文件的上传
            * */
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //完成文件的上传
                    try{
                        InputStream is = socket.getInputStream();
                        File file=new File("D:\\upload");
                        if(!file.exists()){
                            file.mkdirs();
                        }
                        /*
                         * 自定义一个文件的命名规则:防止文件名被覆盖
                         * 规则:域名+毫秒值+随机数
                         * */
                        String fileName="gkx"+System.currentTimeMillis()+new Random().nextInt(99999)+".jpg";
                        //FileOutputStream fos=new FileOutputStream(file+"\\1.jpg");
                        FileOutputStream fos=new FileOutputStream(file+"\\"+fileName);
                        int len=0;
                        byte[] bytes=new byte[1024];
                        while((len=is.read(bytes))!=-1){
                            fos.write(bytes,0,len);
                        }
                        socket.getOutputStream().write("上传成功".getBytes());
                        fos.close();
                        socket.close();
                    }catch (IOException e){
                        System.out.println(e);
                    }
                }
            }).start();
        }
    }
}

模拟B/S服务器分析:

/*
* 创建BS版本TCP服务器
* */
public class TCPServer {
    public static void main(String[] args) throws IOException {
        //创建一个服务器ServerSocket,和系统要指定的端口号
        ServerSocket server=new ServerSocket(8080);
        //使用accept方法获取到请求的客户端对象(浏览器)
        Socket socket = server.accept();
        //使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
        InputStream is = socket.getInputStream();
        //使用网络字节输入流InputStream对象中的方法read读取客户端的请求信息
        byte[] bytes=new byte[1024];
        int len=0;
        while((len=is.read(bytes))!=-1){
            System.out.println(new String(bytes,0,len));
        }
    }
}

客户端是浏览器-》访问服务器-》

读取客户端的请求信息

GET / NET/web/index.html HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Upgrade-Insecure-Requests: 1

服务器要给客户端回写一个信息,回写一个html页面(文件)

我们需要读取html文件,就必须要知道这个文件的地址,而这个地址就是请求信息的第一行GET / NET/web/index.html HTTP/1.1

可以使用BufferedReader中的方法readLine读取一行

new BufferedReader(new InputStream(is));   把网络字节输入流转换为字符缓冲输入流

GET /NET/web/index.html HTTP/1.1

可以使用String类的方法split(" ")切割字符串,获取中间的部分

数组的arr[1]:   /NET/web/index.html

使用String类的方法subString(1),获取html文件的路径:NET/web/index.html

服务器创建一个本地的字节输入流,根据获取到的文件路径,读取html文件

//写入HTTP协议响应头,固定写法

out.write("HTTP/1.1  200  OK\r\n".getBytes());

out.write("Content- Type:text/html\r\n".getBytes());

//必须要写入空行,否则浏览器不解析

out.write("\r\n".getBytes());

服务器端使用网络字节输出流把读取到的文件写入到客户端(浏览器)上显示

模拟B/S服务器代码实现:

/*
* 创建BS版本TCP服务器
* */
public class TCPServer {
    public static void main(String[] args) throws IOException {
        //创建一个服务器ServerSocket,和系统要指定的端口号
        ServerSocket server=new ServerSocket(8080);
        /*
        * 浏览器解析服务器回写的html页面,页面中如果有图片,那么浏览器就会单独的开启一个线程,读取服务器的图片
        * 我们就得让服务器一直处于监听状态,客户端请求一次服务器就得回写一次
        * */
        while(true){
            //使用accept方法获取到请求的客户端对象(浏览器)
            Socket socket = server.accept();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try{
                        //使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
                        InputStream is = socket.getInputStream();
                        //使用网络字节输入流InputStream对象中的方法read读取客户端的请求信息
                        /* byte[] bytes=new byte[1024];
                        int len=0;
                        while((len=is.read(bytes))!=-1){
                        System.out.println(new String(bytes,0,len));
                        }*/
                        //把is网络字节输入流对象,转换为字节缓冲输入流
                        BufferedReader br=new BufferedReader(new InputStreamReader(is));
                        //把客户端请求信息的第一行读出来
                        String line = br.readLine();
                        //把读取的信息进行切割,只要中间的部分
                        String[] arr = line.split(" ");
                        //把路径前面的/去掉,进行截取
                        String htmlpath = arr[1].substring(1);
                        //创建一个本地字节输入流,构造方法中绑定要读取的html路径
                        FileInputStream fis=new FileInputStream(htmlpath);
                        //使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
                        OutputStream os = socket.getOutputStream();
                        //写入HTTP协议响应头,固定写法
                        os.write("HTTP/1.1  200  OK\r\n".getBytes());
                        os.write("Content- Type:text/html\r\n".getBytes());
                        //必须要写入空行,否则浏览器不解析
                        os.write("\r\n".getBytes());
                        //一读一写复制文件,把服务器读取的html文件回写到客户端
                        int len=0;
                        byte[] bytes=new byte[1024];
                        while((len=fis.read(bytes))!=-1){
                            os.write(bytes,0,len);
                        }
                        //释放资源
                        fis.close();
                        socket.close();
                    }catch(IOException e){
                        System.out.println(e);
                    }

                }
            }).start();

        }
    }
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值