Android:如何将.mp3文件上传到http服务器?

19

我想从设备上传只有.mp3文件到服务器。

我想浏览媒体数据的路径并选择任意mp3文件进行上传。

我该如何操作?


1
什么是PHP服务器?你是指HTTP服务器吗? - d-_-b
4个回答

37

以下是我用于将Android手机SD卡上的文件上传到自己的Web服务器的JAVA和PHP代码。

Java/Android 代码:

private void doFileUpload() {

    HttpURLConnection conn = null;
    DataOutputStream dos = null;
    DataInputStream inStream = null;
    String existingFileName = Environment.getExternalStorageDirectory().getAbsolutePath() + "/mypic.png";
    String lineEnd = "\r\n";
    String twoHyphens = "--";
    String boundary = "*****";
    int bytesRead, bytesAvailable, bufferSize;
    byte[] buffer;
    int maxBufferSize = 1 * 1024 * 1024;
    String responseFromServer = "";
    String urlString = "http://mywebsite.com/directory/upload.php";

    try {

        //------------------ CLIENT REQUEST
        FileInputStream fileInputStream = new FileInputStream(new File(existingFileName));
        // open a URL connection to the Servlet
        URL url = new URL(urlString);
        // Open a HTTP connection to the URL
        conn = (HttpURLConnection) url.openConnection();
        // Allow Inputs
        conn.setDoInput(true);
        // Allow Outputs
        conn.setDoOutput(true);
        // Don't use a cached copy.
        conn.setUseCaches(false);
        // Use a post method.
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Connection", "Keep-Alive");
        conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
        dos = new DataOutputStream(conn.getOutputStream());
        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + existingFileName + "\"" + lineEnd);
        dos.writeBytes(lineEnd);
        // create a buffer of maximum size
        bytesAvailable = fileInputStream.available();
        bufferSize = Math.min(bytesAvailable, maxBufferSize);
        buffer = new byte[bufferSize];
        // read file and write it into form...
        bytesRead = fileInputStream.read(buffer, 0, bufferSize);

        while (bytesRead > 0) {

            dos.write(buffer, 0, bufferSize);
            bytesAvailable = fileInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);

        }

        // send multipart form data necesssary after file data...
        dos.writeBytes(lineEnd);
        dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
        // close streams
        Log.e("Debug", "File is written");
        fileInputStream.close();
        dos.flush();
        dos.close();

    } catch (MalformedURLException ex) {
        Log.e("Debug", "error: " + ex.getMessage(), ex);
    } catch (IOException ioe) {
        Log.e("Debug", "error: " + ioe.getMessage(), ioe);
    }

    //------------------ read the SERVER RESPONSE
    try {

        inStream = new DataInputStream(conn.getInputStream());
        String str;

        while ((str = inStream.readLine()) != null) {

            Log.e("Debug", "Server Response " + str);

        }

        inStream.close();

    } catch (IOException ioex) {
        Log.e("Debug", "error: " + ioex.getMessage(), ioex);
    }
}

要放在您服务器上的相关PHP代码(upload.php):

<?php
// Where the file is going to be placed 
$target_path = "uploads/";

/* Add the original filename to our target path.  
Result is "uploads/filename.extension" */
$target_path = $target_path . basename( $_FILES['uploadedfile']['name']); 

if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
    echo "The file ".  basename( $_FILES['uploadedfile']['name']). 
    " has been uploaded";
    chmod ("uploads/".basename( $_FILES['uploadedfile']['name']), 0644);
} else{
    echo "There was an error uploading the file, please try again!";
    echo "filename: " .  basename( $_FILES['uploadedfile']['name']);
    echo "target_path: " .$target_path;
}
?>

需要注意的事项。
1)"mypic.png"必须位于SD卡的根目录中。也就是说,如果你通过Mass Storage USB视图查看Android设备,你需要将文件放在你所遇到的第一个目录中。

2)手机上必须关闭USB MASS STORAGE!或者完全断开与编写代码的计算机的连接,以确保这一点。

3)我不得不在与我的php文件相同的目录中创建一个名为"uploads"的文件夹。

4)显而易见,你必须将我写成http://mywebsite.com/directory/upload.php的网址更改为你自己的网站。


很棒的示例代码 :-) 在我的情况下,我首先需要进行基本身份验证,这可以通过以下方式轻松处理:'Authenticator.setDefault(new Authenticator(){       protected PasswordAuthentication getPasswordAuthentication(){           return new PasswordAuthentication("username","password".toCharArray());       }  });' 我想其他人可能会对了解我的解决方案感兴趣。 - Lasse Samson
@Keaton,我的文件正在上传,但上传的文件大小始终为0。可能是什么问题?我使用了与此链接相同的源代码:http://reecon.wordpress.com/2010/04/25/uploading-files-to-http-server-using-post-android-sdk/。先感谢您。 - AnujAroshA
@Keaton 抱歉打扰你了。我找到错误了。我只是把大于号放反了 :-) - AnujAroshA
关于要放在您的服务器上的相关PHP代码(upload.php):如何构建Java Servlet版本? - Jeff Bootsholz
我的PHP代码无法正常工作。我收到了以下回复。我正在上传一个mp4文件。服务器响应:上传文件时出现错误,请重试!文件名:VID_20130730_100113.mp4 目标路径:uploads/VID_20130730_100113.mp4 有什么建议吗? - Chrishan
显示剩余6条评论

6

感谢Keaton的好建议。

我稍微调整了Java代码,使其可以使用并添加对其他URL参数的支持:

public class HttpMultipartUpload {
    static String lineEnd = "\r\n";
    static String twoHyphens = "--";
    static String boundary = "AaB03x87yxdkjnxvi7";

    public static String upload(URL url, File file, String fileParameterName, HashMap<String, String> parameters)
            throws IOException {
        HttpURLConnection conn = null;
        DataOutputStream dos = null;
        DataInputStream dis = null;
        FileInputStream fileInputStream = null;

        byte[] buffer;
        int maxBufferSize = 20 * 1024;
        try {
            //------------------ CLIENT REQUEST
            fileInputStream = new FileInputStream(file);

            // open a URL connection to the Servlet
            // Open a HTTP connection to the URL
            conn = (HttpURLConnection) url.openConnection();
            // Allow Inputs
            conn.setDoInput(true);
            // Allow Outputs
            conn.setDoOutput(true);
            // Don't use a cached copy.
            conn.setUseCaches(false);
            // Use a post method.
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);

            dos = new DataOutputStream(conn.getOutputStream());

            dos.writeBytes(twoHyphens + boundary + lineEnd);
            dos.writeBytes("Content-Disposition: form-data; name=\"" + fileParameterName
                    + "\"; filename=\"" + file.toString() + "\"" + lineEnd);
            dos.writeBytes("Content-Type: text/xml" + lineEnd);
            dos.writeBytes(lineEnd);

            // create a buffer of maximum size
            buffer = new byte[Math.min((int) file.length(), maxBufferSize)];
            int length;
            // read file and write it into form...
            while ((length = fileInputStream.read(buffer)) != -1) {
                dos.write(buffer, 0, length);
            }

            for (String name : parameters.keySet()) {
                dos.writeBytes(lineEnd);
                dos.writeBytes(twoHyphens + boundary + lineEnd);
                dos.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"" + lineEnd);
                dos.writeBytes(lineEnd);
                dos.writeBytes(parameters.get(name));
            }

            // send multipart form data necessary after file data...
            dos.writeBytes(lineEnd);
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
            dos.flush();
        } finally {
            if (fileInputStream != null) fileInputStream.close();
            if (dos != null) dos.close();
        }

        //------------------ read the SERVER RESPONSE
        try {
            dis = new DataInputStream(conn.getInputStream());
            StringBuilder response = new StringBuilder();

            String line;
            while ((line = dis.readLine()) != null) {
                response.append(line).append('\n');
            }

            return response.toString();
        } finally {
            if (dis != null) dis.close();
        }
    }
}

1
fileParameterName 在这里是什么意思?它是文件格式吗? - rupesh
你好,我正在尝试运行这段代码,但是它对我不起作用。我正在尝试上传音频文件,但它不应该在浏览器中播放。 - Mayur Patel
五年过去了,现在有很多简单的解决方案来执行HTTP上传,而且HTTP本身也已经发展(HTTP 2)。我建议您使用OkHttp。 - Pierre-Luc Paour

1
请注意,如果您复制并粘贴上述PHP代码,任何人都可以上传恶意PHP脚本到您的服务器并运行它,请始终注意这一点,并使用PHP在服务器端检查扩展名,这里和网络上有数千个示例可供参考。此外,为了增加安全性,请在您的Apache、Nginx服务器中添加规则以添加Content-Disposition头(jpg、png、gif、???),并且不要解析上传文件夹中的PHP代码。
例如,在nxgin中,它可能是这样的...
#add header Content-Disposition
location ^~ /upload/pictures {

        default_type application/octet-stream;

    types {
            image/gif     gif;
            image/jpeg    jpg;
            image/png    png;
    }

    add_header X-Content-Type-Options 'nosniff';

    if ($request_filename ~ /(((?!\.(jpg)|(png)|(gif)$)[^/])+$)) {
        add_header Content-Disposition 'attachment; filename="$1"';
            # Add X-Content-Type-Options again, as using add_header in a new context
            # dismisses all previous add_header calls:
            add_header X-Content-Type-Options 'nosniff';
        }
}

#do NOT parse PHP script on the upload folder
location ~ \.php$ {
    try_files $uri =404;
    include /etc/nginx/fastcgi_params;
    #if is the upload folder DO NOT parse PHP scripts on it
    if ($uri !~ "^/upload/pictures") {
        fastcgi_pass unix:/var/run/php-fastcgi/php-fastcgi.socket;
    }
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

0

我知道这个问题已经被问了一段时间。我试图实现同样的功能,在尝试了许多解决方案后,我发现@Keaton的代码对我有效,但它会阻塞我的UI(我正在使用Android Studio 2.1.2),所以我不得不将其包装在AsyncTask中。

因此,使用@Keaton的代码,我有了这个。

从我的onClickListener()中:

private View.OnClickListener btnUpload = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        new doFileUpload().execute();
    }
};

然后是AsyncTask

public class doFileUpload extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... params) {

        <Keaton's code>

     return null;
   }
}

我希望这能帮到任何遇到和我一样问题的人。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接