iodataconnection.java

来自「JAVA FTP 上传下载 的源文件」· Java 代码 · 共 307 行

JAVA
307
字号
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements.  See the NOTICE file * distributed with this work for additional information * regarding copyright ownership.  The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License.  You may obtain a copy of the License at * *  http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied.  See the License for the * specific language governing permissions and limitations * under the License. */package org.apache.ftpserver.impl;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.Writer;import java.net.Socket;import java.util.zip.DeflaterOutputStream;import java.util.zip.InflaterInputStream;import org.apache.ftpserver.ftplet.DataConnection;import org.apache.ftpserver.ftplet.DataType;import org.apache.ftpserver.ftplet.FtpSession;import org.apache.ftpserver.usermanager.impl.TransferRateRequest;import org.apache.ftpserver.util.IoUtils;/** * <strong>Internal class, do not use directly.</strong> *  * An active open data connection, used for transfering data over the data * connection. * * @author The Apache MINA Project (dev@mina.apache.org) * @version $Rev$, $Date$ */public class IODataConnection implements DataConnection {    private static final byte[] EOL = System.getProperty("line.separator").getBytes();        private FtpIoSession session;    private Socket socket;    private ServerDataConnectionFactory factory;    public IODataConnection(final Socket socket, final FtpIoSession session,            final ServerDataConnectionFactory factory) {        this.session = session;        this.socket = socket;        this.factory = factory;    }    /**     * Get data input stream. The return value will never be null.     */    private InputStream getDataInputStream() throws IOException {        try {            // get data socket            Socket dataSoc = socket;            if (dataSoc == null) {                throw new IOException("Cannot open data connection.");            }            // create input stream            InputStream is = dataSoc.getInputStream();            if (factory.isZipMode()) {                is = new InflaterInputStream(is);            }            return is;        } catch (IOException ex) {            factory.closeDataConnection();            throw ex;        }    }    /**     * Get data output stream. The return value will never be null.     */    private OutputStream getDataOutputStream() throws IOException {        try {            // get data socket            Socket dataSoc = socket;            if (dataSoc == null) {                throw new IOException("Cannot open data connection.");            }            // create output stream            OutputStream os = dataSoc.getOutputStream();            if (factory.isZipMode()) {                os = new DeflaterOutputStream(os);            }            return os;        } catch (IOException ex) {            factory.closeDataConnection();            throw ex;        }    }    /*     * (non-Javadoc)     *      * @seeorg.apache.ftpserver.FtpDataConnection2#transferFromClient(java.io.     * OutputStream)     */    public final long transferFromClient(FtpSession session,            final OutputStream out) throws IOException {        TransferRateRequest transferRateRequest = new TransferRateRequest();        transferRateRequest = (TransferRateRequest) session.getUser()                .authorize(transferRateRequest);        int maxRate = 0;        if (transferRateRequest != null) {            maxRate = transferRateRequest.getMaxUploadRate();        }        InputStream is = getDataInputStream();        try {            return transfer(session, false, is, out, maxRate);        } finally {            IoUtils.close(is);        }    }    /*     * (non-Javadoc)     *      * @see     * org.apache.ftpserver.FtpDataConnection2#transferToClient(java.io.InputStream     * )     */    public final long transferToClient(FtpSession session, final InputStream in)            throws IOException {        TransferRateRequest transferRateRequest = new TransferRateRequest();        transferRateRequest = (TransferRateRequest) session.getUser()                .authorize(transferRateRequest);        int maxRate = 0;        if (transferRateRequest != null) {            maxRate = transferRateRequest.getMaxDownloadRate();        }        OutputStream out = getDataOutputStream();        try {            return transfer(session, true, in, out, maxRate);        } finally {            IoUtils.close(out);        }    }    /*     * (non-Javadoc)     *      * @see     * org.apache.ftpserver.FtpDataConnection2#transferToClient(java.lang.String     * )     */    public final void transferToClient(FtpSession session, final String str)            throws IOException {        OutputStream out = getDataOutputStream();        Writer writer = null;        try {            writer = new OutputStreamWriter(out, "UTF-8");            writer.write(str);            // update session            if (session instanceof DefaultFtpSession) {                ((DefaultFtpSession) session).increaseWrittenDataBytes(str                        .getBytes("UTF-8").length);            }        } finally {            if (writer != null) {                writer.flush();            }            IoUtils.close(writer);        }    }    private final long transfer(FtpSession session, boolean isWrite,            final InputStream in, final OutputStream out, final int maxRate)            throws IOException {        long transferredSize = 0L;        boolean isAscii = session.getDataType() == DataType.ASCII;        long startTime = System.currentTimeMillis();        byte[] buff = new byte[4096];        BufferedInputStream bis = null;        BufferedOutputStream bos = null;        try {            bis = IoUtils.getBufferedInputStream(in);            bos = IoUtils.getBufferedOutputStream(out);            DefaultFtpSession defaultFtpSession = null;            if (session instanceof DefaultFtpSession) {                defaultFtpSession = (DefaultFtpSession) session;            }            byte lastByte = 0;            while (true) {                // if current rate exceeds the max rate, sleep for 50ms                // and again check the current transfer rate                if (maxRate > 0) {                    // prevent "divide by zero" exception                    long interval = System.currentTimeMillis() - startTime;                    if (interval == 0) {                        interval = 1;                    }                    // check current rate                    long currRate = (transferredSize * 1000L) / interval;                    if (currRate > maxRate) {                        try {                            Thread.sleep(50);                        } catch (InterruptedException ex) {                            break;                        }                        continue;                    }                }                // read data                int count = bis.read(buff);                if (count == -1) {                    break;                }                // update MINA session                if (defaultFtpSession != null) {                    if (isWrite) {                        defaultFtpSession.increaseWrittenDataBytes(count);                    } else {                        defaultFtpSession.increaseReadDataBytes(count);                    }                }                // write data                // if ascii, replace \n by \r\n                if (isAscii) {                    for (int i = 0; i < count; ++i) {                        byte b = buff[i];                        if(isWrite) {                            if (b == '\n' && lastByte != '\r') {                                bos.write('\r');                            }                                bos.write(b);                        } else {                            if(b == '\n') {                                // for reads, we should always get \r\n                                // so what we do here is to ignore \n bytes                                 // and on \r dump the system local line ending                            } else if(b == '\r') {                                bos.write(EOL);                            } else {                                // not a line ending, just output                                bos.write(b);                            }                        }                        // store this byte so that we can compare it for line endings                        lastByte = b;                    }                } else {                    bos.write(buff, 0, count);                }                transferredSize += count;                notifyObserver();            }        } finally {            if (bos != null) {                bos.flush();            }        }        return transferredSize;    }    /**     * Notify connection manager observer.     */    protected void notifyObserver() {        session.updateLastAccessTime();        // TODO this has been moved from AbstractConnection, do we need to keep        // it?        // serverContext.getConnectionManager().updateConnection(this);    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?