JAVA实现的简易FTP站点

来源:互联网 发布:尼古拉斯赵四 知乎 编辑:程序博客网 时间:2024/06/05 16:04

在JAVA Socket的基础上增加了一些简单的功能,现在已经能够生成本地文件目录,提供文件下载了.

http://blog.csdn.net/coldcoding/article/details/53192607
在这个服务器的代码里增加了

目录生成部分,这些部分将在需要返回目录时起作用

public void doGet() throws IOException{        //资源地址        StringBuffer sb = new StringBuffer(root);          sb.append(clientRequest.getRequestURI());         locaURI = sb.toString();        assert locaURI != null:"返回出错";        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式        System.out.print(df.format(new Date()) +"   ");// new Date()为获取当前系统时间        System.out.println(locaURI);        OutputStream out = responseSocket.getOutputStream();        //消息头        out.write("HTTP/1.0 200 OK\r\n".getBytes());        out.write("\r\n".getBytes());       // 根据 HTTP 协议, 空行将结束头信息        byte[] data = new byte[1024];       //缓冲区        int length = -1;        out.flush();        if(locaURI.endsWith("/")){      //返回目录            InputStream input = new BufferedInputStream(new FileInputStream(this.root + "/GenerateIndex.html"));            while((length = input.read(data)) != -1){                out.write(data, 0, length);                out.flush();            }            /*TODO根据目录构建索引*/            createDirect(this.locaURI,out);            input.close();            out.close();        }else{                      //返回文件            if(locaURI != null){                InputStream input = new BufferedInputStream(new FileInputStream(this.locaURI));                while((length = input.read(data)) != -1){                    out.write(data, 0, length);                    out.flush();                }                input.close();                out.close();             }        }    }public void createDirect(String path,OutputStream out) throws IOException{        //参数检查        //目录生成和写入        assert path != null:"生成目录出错";          File file = new File(path);        if (file.exists()) {            //头部            out.write(("</script><script>start(\"" + path + "\");</script>").getBytes());            out.write("<script>addRow(\"..\",\"..\",0,\"0 B\",\"\");</script>".getBytes());            out.flush();            File[] files = file.listFiles();            if (files.length == 0){                return;            }else{                for (File file2 : files){                    StringBuffer sb = new StringBuffer("\"");                    sb.append(file2.getName().replaceAll("\\/", ""));                    sb.append("\",\"");                    sb.append(file2.getName());                    if(file2.isDirectory())                        sb.append("\",1,\"");                    else                        sb.append("\",0,\"");                    sb.append(file2.getTotalSpace());                    sb.append("\",\"");                    sb.append(file2.lastModified());                    sb.append("\"");                    out.write("<script>addRow(".getBytes());//HTML的结尾添加addRow                    out.write(sb.toString().getBytes());                    out.write(");</script>".getBytes());                    out.flush();                }            }        }    }

HTML文件会使用function addRow(name, url, isdir, size, date_modified)来生成要显示的内容,因此在返回HTML文件之后,在末尾写入需要的内容就行了

<!DOCTYPE html><html i18n-values="dir:textdirection;lang:language"><head><meta charset="utf-8"><meta name="google" value="notranslate"><script>function addRow(name, url, isdir, size, date_modified) {  if (name == ".")    return;  var root = document.location.pathname;  if (root.substr(-1) !== "/")    root += "/";  var table = document.getElementById("table");  var row = document.createElement("tr");  var file_cell = document.createElement("td");  var link = document.createElement("a");  link.className = isdir ? "icon dir" : "icon file";  if (name == "..") {    link.href = root + "..";    link.innerText = document.getElementById("parentDirText").innerText;    link.className = "icon up";    size = "";    date_modified = "";  } else {    if (isdir) {      name = name + "/";      url = url + "/";      size = "";    } else {      link.draggable = "true";      link.addEventListener("dragstart", onDragStart, false);    }    link.innerText = name;    link.href = root + url;  }  file_cell.appendChild(link);  row.appendChild(file_cell);  row.appendChild(createCell(size));  row.appendChild(createCell(date_modified));  table.appendChild(row);}function onDragStart(e) {  var el = e.srcElement;  var name = el.innerText.replace(":", "");  var download_url_data = "application/octet-stream:" + name + ":" + el.href;  e.dataTransfer.setData("DownloadURL", download_url_data);  e.dataTransfer.effectAllowed = "copy";}function createCell(text) {  var cell = document.createElement("td");  cell.setAttribute("class", "detailsColumn");  cell.innerText = text;  return cell;}function start(location) {  var header = document.getElementById("header");  header.innerText = header.innerText.replace("LOCATION", location);  document.getElementById("title").innerText = header.innerText;}function onListingParsingError() {  var box = document.getElementById("listingParsingErrorBox");  box.innerHTML = box.innerHTML.replace("LOCATION", encodeURI(document.location)      + "?raw");  box.style.display = "block";}</script><style>  h1 {    border-bottom: 1px solid #c0c0c0;    margin-bottom: 10px;    padding-bottom: 10px;    white-space: nowrap;  }  table {    border-collapse: collapse;  }  tr.header {    font-weight: bold;  }  td.detailsColumn {    -webkit-padding-start: 2em;    text-align: end;    white-space: nowrap;  }  a.icon {    -webkit-padding-start: 1.5em;    text-decoration: none;  }  a.icon:hover {    text-decoration: underline;  }  a.file {    background : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC ") left top no-repeat;  }  a.dir {    background : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqMU79rFUEQ/vbuodFEEkzAImBpkUabFP4ldpaJhZXYm/RiZWsv/hkWFglBUyTIgyAIIfgIRjHv3r39MePM7N3LcbxAFvZ2b2bn22/mm3XMjF+HL3YW7q28YSIw8mBKoBihhhgCsoORot9d3/ywg3YowMXwNde/PzGnk2vn6PitrT+/PGeNaecg4+qNY3D43vy16A5wDDd4Aqg/ngmrjl/GoN0U5V1QquHQG3q+TPDVhVwyBffcmQGJmSVfyZk7R3SngI4JKfwDJ2+05zIg8gbiereTZRHhJ5KCMOwDFLjhoBTn2g0ghagfKeIYJDPFyibJVBtTREwq60SpYvh5++PpwatHsxSm9QRLSQpEVSd7/TYJUb49TX7gztpjjEffnoVw66+Ytovs14Yp7HaKmUXeX9rKUoMoLNW3srqI5fWn8JejrVkK0QcrkFLOgS39yoKUQe292WJ1guUHG8K2o8K00oO1BTvXoW4yasclUTgZYJY9aFNfAThX5CZRmczAV52oAPoupHhWRIUUAOoyUIlYVaAa/VbLbyiZUiyFbjQFNwiZQSGl4IDy9sO5Wrty0QLKhdZPxmgGcDo8ejn+c/6eiK9poz15Kw7Dr/vN/z6W7q++091/AQYA5mZ8GYJ9K0AAAAAASUVORK5CYII= ") left top no-repeat;  }  a.up {    background : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU0toU0EUPfPysx/tTxuDH9SCWhUDooIbd7oRUUTMouqi2iIoCO6lceHWhegy4EJFinWjrlQUpVm0IIoFpVDEIthm0dpikpf3ZuZ6Z94nrXhhMjM3c8895977BBHB2PznK8WPtDgyWH5q77cPH8PpdXuhpQT4ifR9u5sfJb1bmw6VivahATDrxcRZ2njfoaMv+2j7mLDn93MPiNRMvGbL18L9IpF8h9/TN+EYkMffSiOXJ5+hkD+PdqcLpICWHOHc2CC+LEyA/K+cKQMnlQHJX8wqYG3MAJy88Wa4OLDvEqAEOpJd0LxHIMdHBziowSwVlF8D6QaicK01krw/JynwcKoEwZczewroTvZirlKJs5CqQ5CG8pb57FnJUA0LYCXMX5fibd+p8LWDDemcPZbzQyjvH+Ki1TlIciElA7ghwLKV4kRZstt2sANWRjYTAGzuP2hXZFpJ/GsxgGJ0ox1aoFWsDXyyxqCs26+ydmagFN/rRjymJ1898bzGzmQE0HCZpmk5A0RFIv8Pn0WYPsiu6t/Rsj6PauVTwffTSzGAGZhUG2F06hEc9ibS7OPMNp6ErYFlKavo7MkhmTqCxZ/jwzGA9Hx82H2BZSw1NTN9Gx8ycHkajU/7M+jInsDC7DiaEmo1bNl1AMr9ASFgqVu9MCTIzoGUimXVAnnaN0PdBBDCCYbEtMk6wkpQwIG0sn0PQIUF4GsTwLSIFKNqF6DVrQq+IWVrQDxAYQC/1SsYOI4pOxKZrfifiUSbDUisif7XlpGIPufXd/uvdvZm760M0no1FZcnrzUdjw7au3vu/BVgAFLXeuTxhTXVAAAAAElFTkSuQmCC ") left top no-repeat;  }  html[dir=rtl] a {    background-position-x: right;  }  #listingParsingErrorBox {    border: 1px solid black;    background: #fae691;    padding: 10px;    display: none;  }</style><title id="title"></title></head><body><div id="listingParsingErrorBox" i18n-values=".innerHTML:listingParsingErrorBoxText"></div><span id="parentDirText" style="display:none" i18n-content="parentDirText"></span><h1 id="header" i18n-content="header"></h1><table id="table">  <tr class="header">    <td i18n-content="headerName"></td>    <td class="detailsColumn" i18n-content="headerSize"></td>    <td class="detailsColumn" i18n-content="headerDateModified"></td>  </tr></table></body></html><script>// Copyright (c) 2012 The Chromium Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file./** * @fileoverview This file defines a singleton which provides access to all data * that is available as soon as the page's resources are loaded (before DOM * content has finished loading). This data includes both localized strings and * any data that is important to have ready from a very early stage (e.g. things * that must be displayed right away). */var loadTimeData;// Expose this type globally as a temporary work around until// https://github.com/google/closure-compiler/issues/544 is fixed./** @constructor */function LoadTimeData() {}(function() {  'use strict';  LoadTimeData.prototype = {    /**     * Sets the backing object.     *     * Note that there is no getter for |data_| to discourage abuse of the form:     *     *     var value = loadTimeData.data()['key'];     *     * @param {Object} value The de-serialized page data.     */    set data(value) {      expect(!this.data_, 'Re-setting data.');      this.data_ = value;    },    /**     * Returns a JsEvalContext for |data_|.     * @returns {JsEvalContext}     */    createJsEvalContext: function() {      return new JsEvalContext(this.data_);    },    /**     * @param {string} id An ID of a value that might exist.     * @return {boolean} True if |id| is a key in the dictionary.     */    valueExists: function(id) {      return id in this.data_;    },    /**     * Fetches a value, expecting that it exists.     * @param {string} id The key that identifies the desired value.     * @return {*} The corresponding value.     */    getValue: function(id) {      expect(this.data_, 'No data. Did you remember to include strings.js?');      var value = this.data_[id];      expect(typeof value != 'undefined', 'Could not find value for ' + id);      return value;    },    /**     * As above, but also makes sure that the value is a string.     * @param {string} id The key that identifies the desired string.     * @return {string} The corresponding string value.     */    getString: function(id) {      var value = this.getValue(id);      expectIsType(id, value, 'string');      return /** @type {string} */ (value);    },    /**     * Returns a formatted localized string where $1 to $9 are replaced by the     * second to the tenth argument.     * @param {string} id The ID of the string we want.     * @param {...string} var_args The extra values to include in the formatted     *     output.     * @return {string} The formatted string.     */    getStringF: function(id, var_args) {      var value = this.getString(id);      if (!value)        return '';      var varArgs = arguments;      return value.replace(/\$[$1-9]/g, function(m) {        return m == '$$' ? '$' : varArgs[m[1]];      });    },    /**     * As above, but also makes sure that the value is a boolean.     * @param {string} id The key that identifies the desired boolean.     * @return {boolean} The corresponding boolean value.     */    getBoolean: function(id) {      var value = this.getValue(id);      expectIsType(id, value, 'boolean');      return /** @type {boolean} */ (value);    },    /**     * As above, but also makes sure that the value is an integer.     * @param {string} id The key that identifies the desired number.     * @return {number} The corresponding number value.     */    getInteger: function(id) {      var value = this.getValue(id);      expectIsType(id, value, 'number');      expect(value == Math.floor(value), 'Number isn\'t integer: ' + value);      return /** @type {number} */ (value);    },    /**     * Override values in loadTimeData with the values found in |replacements|.     * @param {Object} replacements The dictionary object of keys to replace.     */    overrideValues: function(replacements) {      expect(typeof replacements == 'object',             'Replacements must be a dictionary object.');      for (var key in replacements) {        this.data_[key] = replacements[key];      }    }  };  /**   * Checks condition, displays error message if expectation fails.   * @param {*} condition The condition to check for truthiness.   * @param {string} message The message to display if the check fails.   */  function expect(condition, message) {    if (!condition) {      console.error('Unexpected condition on ' + document.location.href + ': ' +                    message);    }  }  /**   * Checks that the given value has the given type.   * @param {string} id The id of the value (only used for error message).   * @param {*} value The value to check the type on.   * @param {string} type The type we expect |value| to be.   */  function expectIsType(id, value, type) {    expect(typeof value == type, '[' + value + '] (' + id +                                 ') is not a ' + type);  }  expect(!loadTimeData, 'should only include this file once');  loadTimeData = new LoadTimeData;})();</script><script>loadTimeData.data = {"header":"LOCATION 的索引","headerDateModified":"修改日期","headerName":"名称","headerSize":"大小","listingParsingErrorBoxText":"糟糕!Google Chrome无法解读服务器所发送的数据。请\u003Ca href=\"http://code.google.com/p/chromium/issues/entry\">报告错误\u003C/a>,并附上\u003Ca href=\"LOCATION\">原始列表\u003C/a>。","parentDirText":"[上级目录]","textdirection":"ltr"};</script><script>// Copyright (c) 2012 The Chromium Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file.// // Copyright (c) 2012 The Chromium Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file./** @typedef {Document|DocumentFragment|Element} */var ProcessingRoot;/** * @fileoverview This is a simple template engine inspired by JsTemplates * optimized for i18n. * * It currently supports three handlers: * *   * i18n-content which sets the textContent of the element. * *     <span i18n-content="myContent"></span> * *   * i18n-options which generates <option> elements for a <select>. * *     <select i18n-options="myOptionList"></select> * *   * i18n-values is a list of attribute-value or property-value pairs. *     Properties are prefixed with a '.' and can contain nested properties. * *     <span i18n-values="title:myTitle;.style.fontSize:fontSize"></span> * * This file is a copy of i18n_template.js, with minor tweaks to support using * load_time_data.js. It should replace i18n_template.js eventually. */var i18nTemplate = (function() {  /**   * This provides the handlers for the templating engine. The key is used as   * the attribute name and the value is the function that gets called for every   * single node that has this attribute.   * @type {!Object}   */  var handlers = {    /**     * This handler sets the textContent of the element.     * @param {!HTMLElement} element The node to modify.     * @param {string} key The name of the value in |data|.     * @param {!LoadTimeData} data The data source to draw from.     * @param {!Array<ProcessingRoot>} visited     */    'i18n-content': function(element, key, data, visited) {      element.textContent = data.getString(key);    },    /**     * This handler adds options to a <select> element.     * @param {!HTMLElement} select The node to modify.     * @param {string} key The name of the value in |data|. It should     *     identify an array of values to initialize an <option>. Each value,     *     if a pair, represents [content, value]. Otherwise, it should be a     *     content string with no value.     * @param {!LoadTimeData} data The data source to draw from.     * @param {!Array<ProcessingRoot>} visited     */    'i18n-options': function(select, key, data, visited) {      var options = data.getValue(key);      options.forEach(function(optionData) {        var option = typeof optionData == 'string' ?            new Option(optionData) :            new Option(optionData[1], optionData[0]);        select.appendChild(option);      });    },    /**     * This is used to set HTML attributes and DOM properties. The syntax is:     *   attributename:key;     *   .domProperty:key;     *   .nested.dom.property:key     * @param {!HTMLElement} element The node to modify.     * @param {string} attributeAndKeys The path of the attribute to modify     *     followed by a colon, and the name of the value in |data|.     *     Multiple attribute/key pairs may be separated by semicolons.     * @param {!LoadTimeData} data The data source to draw from.     * @param {!Array<ProcessingRoot>} visited     */    'i18n-values': function(element, attributeAndKeys, data, visited) {      var parts = attributeAndKeys.replace(/\s/g, '').split(/;/);      parts.forEach(function(part) {        if (!part)          return;        var attributeAndKeyPair = part.match(/^([^:]+):(.+)$/);        if (!attributeAndKeyPair)          throw new Error('malformed i18n-values: ' + attributeAndKeys);        var propName = attributeAndKeyPair[1];        var propExpr = attributeAndKeyPair[2];        var value = data.getValue(propExpr);        // Allow a property of the form '.foo.bar' to assign a value into        // element.foo.bar.        if (propName[0] == '.') {          var path = propName.slice(1).split('.');          var targetObject = element;          while (targetObject && path.length > 1) {            targetObject = targetObject[path.shift()];          }          if (targetObject) {            targetObject[path] = value;            // In case we set innerHTML (ignoring others) we need to recursively            // check the content.            if (path == 'innerHTML') {              for (var i = 0; i < element.children.length; ++i) {                processWithoutCycles(element.children[i], data, visited, false);              }            }          }        } else {          element.setAttribute(propName, /** @type {string} */(value));        }      });    }  };  var prefixes = [''];  // Only look through shadow DOM when it's supported. As of April 2015, iOS  // Chrome doesn't support shadow DOM.  if (Element.prototype.createShadowRoot)    prefixes.push('* /deep/ ');  var attributeNames = Object.keys(handlers);  var selector = prefixes.map(function(prefix) {    return prefix + '[' + attributeNames.join('], ' + prefix + '[') + ']';  }).join(', ');  /**   * Processes a DOM tree using a |data| source to populate template values.   * @param {!ProcessingRoot} root The root of the DOM tree to process.   * @param {!LoadTimeData} data The data to draw from.   */  function process(root, data) {    processWithoutCycles(root, data, [], true);  }  /**   * Internal process() method that stops cycles while processing.   * @param {!ProcessingRoot} root   * @param {!LoadTimeData} data   * @param {!Array<ProcessingRoot>} visited Already visited roots.   * @param {boolean} mark Whether nodes should be marked processed.   */  function processWithoutCycles(root, data, visited, mark) {    if (visited.indexOf(root) >= 0) {      // Found a cycle. Stop it.      return;    }    // Mark the node as visited before recursing.    visited.push(root);    var importLinks = root.querySelectorAll('link[rel=import]');    for (var i = 0; i < importLinks.length; ++i) {      var importLink = /** @type {!HTMLLinkElement} */(importLinks[i]);      if (!importLink.import) {        // Happens when a <link rel=import> is inside a <template>.        // TODO(dbeam): should we log an error if we detect that here?        continue;      }      processWithoutCycles(importLink.import, data, visited, mark);    }    var templates = root.querySelectorAll('template');    for (var i = 0; i < templates.length; ++i) {      var template = /** @type {HTMLTemplateElement} */(templates[i]);      if (!template.content)        continue;      processWithoutCycles(template.content, data, visited, mark);    }    var isElement = root instanceof Element;    if (isElement && root.webkitMatchesSelector(selector))      processElement(/** @type {!Element} */(root), data, visited);    var elements = root.querySelectorAll(selector);    for (var i = 0; i < elements.length; ++i) {      processElement(elements[i], data, visited);    }    if (mark) {      var processed = isElement ? [root] : root.children;      if (processed) {        for (var i = 0; i < processed.length; ++i) {          processed[i].setAttribute('i18n-processed', '');        }      }    }  }  /**   * Run through various [i18n-*] attributes and populate.   * @param {!Element} element   * @param {!LoadTimeData} data   * @param {!Array<ProcessingRoot>} visited   */  function processElement(element, data, visited) {    for (var i = 0; i < attributeNames.length; i++) {      var name = attributeNames[i];      var attribute = element.getAttribute(name);      if (attribute != null)        handlers[name](element, attribute, data, visited);    }  }  return {    process: process  };}());i18nTemplate.process(document, loadTimeData);</script>
1 0
原创粉丝点击