文件传输

简介: 文件(File)是最常见的数据源之一,在程序中经常需要将数据存储到文件中,例如图片文件、声音文件等数据文件。在实际使用时,文件都包含一个特定的格式,这个格式需要程序员根据需求进行设计。读取已有的文件时也需要熟悉对应的文件格式,才能把数据从文件中正确地读取出来。

文件(File)是最常见的数据源之一,在程序中经常需要将数据存储到文件中,例如图片文件、声音文件等数据文件。在实际使用时,文件都包含一个特定的格式,这个格式需要程序员根据需求进行设计。读取已有的文件时也需要熟悉对应的文件格式,才能把数据从文件中正确地读取出来。

在NIO类库提供之前,Java所有的文件操作分为两大类:

基于字节流的InputStream和OutputStream;

基于字符流的Reader和Writer。

通过NIO新提供的FileChannel类库可以方便地以“管道”方式对文件进行各种I/O操作,相比于传统以流的方式进行的I/O操作有了很大的变化和改进。

FileChannel简介

Java NIO中的FileChannel是一个连接到文件的通道,可以通过这个文件通道读写文件。JDK1.7之前NIO1.0的FileChannel是同步阻塞的,JDK1.7版本对NIO类库进行了升级,升级后的NIO2.0提供了异步文件通道AsynchronousFileChannel,它支持异步非阻塞文件操作(AIO)。

在使用FileChannel之前必须先打开它,FileChannel无法直接被打开,需要通过使用InputStream、OutputStream或RandomAccessFile来获取一个FileChannel实例。下面示范如何通过RandomAccessFile打开FileChannel。

RandomAccessFile billFile = new RandomAccessFile("home/lilinfeng/sms.bill", "rw");
FileChannel channel = billFile.getChannel();

如果需要从FileChannel中读取数据,要申请一个ByteBuffer,将数据从FileChannel中读取到字节缓冲区中。read()方法返回的int值表示有多少字节被读到了字节缓冲区中,如果返回-1,表示读到了文件末尾。如果需要通过FileChannel向文件中写入数据,需要将数据复制或者直接存放到Byte Buffer中,然后调用FileChannel.write()方法进行写操作。

示例代码如下:

String content = "13888888888|北京市海淀区|全球通|VIP用户|";
ByteBuffer writeBuffer = ByteBuffer.allocate(128);
writeBuffer.put(content.getBytes());
writeBuffer.flip();
channel.write(buf);

使用完FileChannel之后,需要通过close()方法关闭文件句柄,防止出现句柄泄漏。

可以通过FileChannel的position(long pos)方法设置文件的位置指针,利用该特性可以实现文件的随机读写。

Netty文件传输开发

在实际项目中,文件传输通常采用FTP或者HTTP附件的方式。事实上通过TCP Socket+File的方式进行文件传输也有一定的应用场景,尽管不是主流,但是掌握这种文件传输方式还是比较重要的,特别是针对两个跨主机的JVM进程之间进行持久化数据的相互交换。

具体场景如下。

(1)Netty文件服务器启动,绑定8080作为内部监听端口;

(2)在CMD控制台,通过telnet和文件服务器建立TCP连接;

(3)控制台输入需要下载的文件绝对路径;

(4)文件服务器接收到请求消息后进行合法性判断,如果文件存在,则将文件发送给CMD控制台;

(5)CMD控制台打印文件名和文件内容。

服务端代码示例:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

public class FileServer {
    public void run(int port) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 100)
                    .childHandler(new ChannelInitializer() {
                        public void initChannel(Channel ch)throws Exception {
                            ch.pipeline().addLast(
                                    //它的作用是将文件内容编码为字符串
                                    new StringEncoder(CharsetUtil.UTF_8),
                                    //在ChannelPipeline中添加了LineBasedFrameDecoder,它能够按照回车换行符对数据报进行解码。
                                    new LineBasedFrameDecoder(1024),
                                    //新增StringDecoder,它的作用是将数据报解码成为字符串,两个解码器组合起来就是文本换行解码器。
                                    new StringDecoder(CharsetUtil.UTF_8),
                                    new FileServerHandler());
                        }
                    });
            ChannelFuture f = b.bind(port).sync();
            System.out.println("Start file server at port : " + port);
            f.channel().closeFuture().sync();
        } finally {
            // 优雅停机
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 8080;
        if (args.length > 0) {
            try {
                port = Integer.parseInt(args[0]);
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }
        new FileServer().run(port);
    }
}

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.DefaultFileRegion;
import io.netty.channel.FileRegion;
import io.netty.channel.SimpleChannelInboundHandler;

import java.io.File;
import java.io.RandomAccessFile;

public class FileServerHandler extends SimpleChannelInboundHandler {

    private static final String CR = System.getProperty("line.separator");

    public void messageReceived(ChannelHandlerContext ctx, Object o) throws Exception {
        String msg = (String) o;
        File file = new File(msg);
        if (file.exists()) {
            //首先对文件的合法性进行校验,如果不存在,构造异常消息返回。
            if (!file.isFile()) {
                ctx.writeAndFlush("Not a file : " + file + CR);
                return;
            }
            ctx.write(file + " " + file.length() + CR);
            //如果文件存在,使用RandomAccessFile以只读的方式打开文件,
            RandomAccessFile randomAccessFile = new RandomAccessFile(msg, "r");
            //通过Netty提供的DefaultFileRegion进行文件传输,
            //它有如下三个参数。
            //FileChannel:文件通道,用于对文件进行读写操作;
            //Position:文件操作的指针位置,读取或者写入的起始点;
            //Count:操作的总字节数。
            FileRegion region = new DefaultFileRegion(
                    randomAccessFile.getChannel(), 0, randomAccessFile.length());
            //直接调用ChannelHandlerContext的write方法实现文件的发送。Netty底层对文件写入进行了封装,上层应用不需要关心发送的细节。
            ctx.write(region);
            // 最后写入回车换行符告知CMD控制台:文件传输结束。
            ctx.writeAndFlush(CR);
            randomAccessFile.close();
        } else {
            ctx.writeAndFlush("File not found: " + file + CR);
        }
    }

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

测试结果:

  doc-dir git:(develop)  telnet localhost 8080
Trying ::1...
Connected to localhost.
Escape character is '^]'.
/Users/***/info.txt
File not found: /Users/***/info.txt
/Users/***/Documents/info.txt     
/Users/***/Documents/info.txt 4355
  RandomStringUtils.random(5, new char[]{'a','b','c','d','e','f'});
 
 /finance/exportofflinerecord?shopSettleBillId=2314&shopId=184
 bills?limit=50&offset=0&lastId=undefined&queryMonth=11&queryYear=2015&shopSettleTime=1&shopType=2&shopValue=184&t=1446705363502
 createOfflineRefundRecordName(shopName, shopSettleBillDTO);

 

目录
相关文章
|
存储 网络协议 安全
使用 NetCat 工具实现远程文件传输
NetCat(NC)是一个通过 TCP/UDP 在网络中进行读写数据工具,主要用于调式领域,传输领域甚至黑客攻击领域。利用 NetCat 工具,可以将网络中的完整数据发送至另一台主机终端显示或存储,常见的应用为文件传输、与好友即时通信、传输流媒体等功能。
498 0
使用 NetCat 工具实现远程文件传输
|
4月前
|
安全 Linux Go
croc-文件传输工具
croc-文件传输工具
|
7月前
|
Linux 网络安全 数据安全/隐私保护
FTP 文件传输服务
FTP 文件传输服务
|
7月前
|
网络协议 安全 网络安全
OpenWRT配置SFTP远程文件传输,让数据分享更安全
OpenWRT配置SFTP远程文件传输,让数据分享更安全
177 0
|
7月前
|
Shell
VBA实现ftp文件传输
VBA实现ftp文件传输
210 0
|
网络安全 开发工具 数据安全/隐私保护
阿里云搭建FTP服务器,完成文件传输
本文主要使用搭建FTP服务器的系统是ubuntu18.04,租的服务器是阿里云服务器(ecs.t6-c1m1.large)。决定想在服务器上搭建FTP主要是为了方便传输文件,网上方法众多,因此我将我从头到尾搭建FTP并且传输文件的步骤和问题记录在此,方便想尝试的人学习。
阿里云搭建FTP服务器,完成文件传输
|
网络协议 安全 Linux
FTP文件传输
FTP文件传输
FTP文件传输
|
安全 数据安全/隐私保护
文件传输解决方案都有哪些?
文件传输是一个通用术语,适用于通过计算机网络传输数据的行为,私有或公共。托管文件传输旨在促进文件传输,它是一种软件或服务,用于通过网络提供安全的内部,外部和临时数据传输。文件传输软件作为使用ad-hoc文件传输解决方案(如FTP,SFTP,HTTP等)的替代方案助力公司企业进行文件传输。
2010 0
|
测试技术 Windows
镭速(Raysync)文件传输对比Filezilla测试!
在传输文件过程中往往由于网络环境问题,容易产生不同的丢包与延时。特别是跨国传输中易产生大的丢包与延时。因此测试一款传输软件特别是有跨国传输场景的,应该模拟软件在大丢包、大延时下对传输速度的影响。 模拟丢包与延时的软件工具有很多,今天介绍下windows下模拟丢包延时的方法。
2008 0