如何使用NanoHTTPD(在Android内)在SD卡上提供文件

我用NanoHTTPD编写了一个小型的Android服务器。 它可以很好地服务一个HTML文件(位于sdcard / www / index.html的网页)。 任何人都可以帮我找出如何使用NanoHTTPD服务audio或video文件,而不是HTML页面? 如果这个问题看起来很愚蠢,请原谅我,因为我是HTTP新手! 这里是我的服务器端代码(我已经replace了audio文件的网页path):

package com.example.zserver; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.Map; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.util.Log; public class MainActivity extends Activity { private WebServer server; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); server = new WebServer(); try { server.start(); } catch(IOException ioe) { Log.w("Httpd", "The server could not start."); } Log.w("Httpd", "Web server initialized."); } @Override public void onDestroy() { super.onDestroy(); if (server != null) server.stop(); } private class WebServer extends NanoHTTPD { public WebServer() { super(8080); } @Override public Response serve(String uri, Method method, Map<String, String> header, Map<String, String> parameters, Map<String, String> files) { String answer = ""; try { // Opening file from SD Card File root = Environment.getExternalStorageDirectory(); FileReader index = new FileReader(root.getAbsolutePath() + "/www/music.mp3"); BufferedReader reader = new BufferedReader(index); String line = ""; while ((line = reader.readLine()) != null) { answer += line; } } catch(IOException ioe) { Log.w("Httpd", ioe.toString()); } return new NanoHTTPD.Response(answer); } } } 

我已经在我的代码中包含了必要的使用权限:

 <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

任何帮助,将不胜感激。 提前致谢!

编辑,新增权限:

 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 

编辑1:读取和写入缓冲区的规范方式:

 int read; int n=1; while((read = dis.read(mybytearray)) != -1){ dos.write(mybytearray, 0, read);} 

Solutions Collecting From Web of "如何使用NanoHTTPD(在Android内)在SD卡上提供文件"

首先,您需要确保在服务媒体文件时正确设置mimetype。

其次,使用FileReader读取MP3文件不会太远,而应该使用InputStream提供NanoHTTPD。

下面是你的代码的一个修改版本,它提供了一个MP3文件。 通过将mimetype设置为audio/mpeg您可以让浏览器决定如何处理这些内容。 例如,在Chrome中,集成的音乐播放器将启动并播放该文件。

 public class StackOverflowMp3Server extends NanoHTTPD { public StackOverflowMp3Server() { super(8089); } @Override public Response serve(String uri, Method method, Map<String, String> header, Map<String, String> parameters, Map<String, String> files) { String answer = ""; FileInputStream fis = null; try { fis = new FileInputStream(Environment.getExternalStorageDirectory() + "/music/musicfile.mp3"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return new NanoHTTPD.Response(Status.OK, "audio/mpeg", fis); } } 

编辑:很多人一直在问如何使音域文件寻找使用范围请求,我将在下面演示

为了使audio文件成为可search的,使用范围请求,使得HTTP客户端能够以块为单位检索audio文件的部分。 确保您正在使用PARTIAL_CONTENT响应状态(HTTP 206)来提供文件。 一个示例实现可以在NanoHTTPD的示例代码中find: SimpleWebserver.java

在我的实现中,我不是直接在serve方法中返回NanoHTTPD Response,而是创build另一个名为“servefile”的方法,我将其用作处理范围请求的响应,如下所示。 这段代码是上面链接的SimpleWebServer.java的修改实现。

  @Override public Response serve(String uri, Method method, Map<String, String> header, Map<String, String> parameters, Map<String, String> files) { File f = new File(Environment.getExternalStorageDirectory() + "/music/musicfile.mp3"); String mimeType = "audio/mpeg"; return serveFile(uri, header, f, mimeType); } //Announce that the file server accepts partial content requests private Response createResponse(Response.Status status, String mimeType, InputStream message) { Response res = new Response(status, mimeType, message); res.addHeader("Accept-Ranges", "bytes"); return res; } /** * Serves file from homeDir and its' subdirectories (only). Uses only URI, * ignores all headers and HTTP parameters. */ private Response serveFile(String uri, Map<String, String> header, File file, String mime) { Response res; try { // Calculate etag String etag = Integer.toHexString((file.getAbsolutePath() + file.lastModified() + "" + file.length()).hashCode()); // Support (simple) skipping: long startFrom = 0; long endAt = -1; String range = header.get("range"); if (range != null) { if (range.startsWith("bytes=")) { range = range.substring("bytes=".length()); int minus = range.indexOf('-'); try { if (minus > 0) { startFrom = Long.parseLong(range .substring(0, minus)); endAt = Long.parseLong(range.substring(minus + 1)); } } catch (NumberFormatException ignored) { } } } // Change return code and add Content-Range header when skipping is // requested long fileLen = file.length(); if (range != null && startFrom >= 0) { if (startFrom >= fileLen) { res = createResponse(Response.Status.RANGE_NOT_SATISFIABLE, NanoHTTPD.MIME_PLAINTEXT, ""); res.addHeader("Content-Range", "bytes 0-0/" + fileLen); res.addHeader("ETag", etag); } else { if (endAt < 0) { endAt = fileLen - 1; } long newLen = endAt - startFrom + 1; if (newLen < 0) { newLen = 0; } final long dataLen = newLen; FileInputStream fis = new FileInputStream(file) { @Override public int available() throws IOException { return (int) dataLen; } }; fis.skip(startFrom); res = createResponse(Response.Status.PARTIAL_CONTENT, mime, fis); res.addHeader("Content-Length", "" + dataLen); res.addHeader("Content-Range", "bytes " + startFrom + "-" + endAt + "/" + fileLen); res.addHeader("ETag", etag); } } else { if (etag.equals(header.get("if-none-match"))) res = createResponse(Response.Status.NOT_MODIFIED, mime, ""); else { res = createResponse(Response.Status.OK, mime, new FileInputStream(file)); res.addHeader("Content-Length", "" + fileLen); res.addHeader("ETag", etag); } } } catch (IOException ioe) { res = createResponse(Response.Status.FORBIDDEN, NanoHTTPD.MIME_PLAINTEXT, "FORBIDDEN: Reading file failed."); } return res; } 

你还不需要添加权限android.permission.READ_EXTERNAL_STORAGE

因为你正在阅读一个文件。