在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>