Help us understand the problem. What is going on with this article?

AndroidでFirebaseStorageに複数のファイルをZipにしてアップロードする。

1.複数のファイルをアップロードできない!

AndroidFirebaseStorageを使っているとき当然複数のファイルを一回にアップロードすることは当然あります。しかし、現在そのようなAPIは提供されていません。困った困った...。ということで複数のファイルをZipにまとめてアップロードすることにしました。

2.実装

SimpleFirebaseStorageDatabase.java
import android.content.Context;
import android.net.Uri;
import android.util.Log;

import androidx.annotation.NonNull;


import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class SimpleFirebaseStorageDatabase {

    private static final String TAG = "SimpleFirebaseStorageDB";
    private String userId;
    private StorageReference storageRef;
    private DatabaseReference databaseRef;
    private Context mContext;

    private static final long MAX_DOWNLOAD_SIZE = 1024 * 1024 * 5;

    public SimpleFirebaseStorageDatabase (Context context, FirebaseAuth mAuth, String firebaseStorageBucketToken) {
        mContext = context;
        FirebaseUser user = mAuth.getCurrentUser();
        if (user == null) {
            return;
        }
        this.userId =  user.getUid();
        storageRef = FirebaseStorage.getInstance().getReferenceFromUrl(firebaseStorageBucketToken).child("users").child(userId);
    }
    public void uploadFilesByTempFile (final String projectName, List<String> uris) {

        File zip = zipFilesToFile(projectName, uris);
        if (zip == null) {
            Log.e(TAG, "No zip file is created: " + projectName);
            return;
        }
        try {
            storageRef.child(projectName).putFile(Uri.fromFile(zip)).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onSuccess (UploadTask.TaskSnapshot taskSnapshot) {
                    Log.d(TAG, "Succeeded to upload project : " + projectName);
                    storageRef.child(projectName).getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                        @Override
                        public void onSuccess (Uri uri) {
                            Log.d(TAG, "Succeeded to get download url : " + uri);
                            onUploadSuccess(uri.toString());
                        }
                    }).addOnFailureListener(new OnFailureListener() {
                        @Override
                        public void onFailure (@NonNull Exception e) {
                            Log.e(TAG, "Failed to get download url : " + projectName, e);
                            onUploadFail();
                        }
                    });
                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure (@NonNull Exception e) {
                    Log.e(TAG, "Failed to upload project : " + projectName, e);
                    onUploadFail();
                }
            });
        } catch (Exception e) {
            onUploadFail();
        }

    }

    private File zipFilesToFile(String projectName, List<String> uris) {
        try {
            File projFile = new File(mContext.getFilesDir(), projectName);
            Log.d(TAG, "Make project zip file: " + projFile.getPath());
            // String outfilePath で出力先のファイルパスが指定されているとする
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(projFile));
            byte[] buffer = new byte[1024 * 4];
            int len = 0;

            // 引数などで String[] files として zip に追加したいファイルのファイルパスが指定されているとする
            for (String uri : uris) {
                zipOneFile(uri, out, buffer);
            }
            out.close();
            Log.d(TAG, "Succeeded to make project zip file: " + projFile.getPath());
            return projFile;
        } catch(Exception e){
            // エラー処理
            Log.e(TAG, "Failed to make project zip file: " + projectName, e);
        }
        return null;
    }


    /**
     * 指定Uriの1ファイルをZIPに追加する。
     * @param uri 圧縮するファイルのパス(Uri)
     * @param os
     * @param buffer
     */
    private static void zipOneFile(String uri, ZipOutputStream os, byte[] buffer) {
        InputStream in = null;
        int len = 0;
        try {
            Log.d(TAG, "Zip one file : " + uri);
            String path = Uri.parse(uri).getPath();
            File inFile = new File(path);
            if (!inFile.exists()) {
                Log.w(TAG, "File doesn't exist: " + uri);
                return;
            }

            in = new FileInputStream(inFile);
            os.putNextEntry(new ZipEntry(inFile.getName())); // path名からファイル名だけにしておく
            while ((len = in.read(buffer)) > 0) {
                os.write(buffer, 0, len);
            }
        } catch (Exception e) {
            Log.e(TAG, "Failed to zip file: " + uri, e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ioe) {
                    // do nothing
                }
            }
        }
    }

    private void onUploadSuccess (String downloadUri) {
        if (mContext instanceof OnFirebaseStorageUploadListener) {
            ((OnFirebaseStorageUploadListener) mContext).onUploadSucceed(downloadUri);
        }
    }

    private void onUploadFail () {
        if (mContext instanceof OnFirebaseStorageUploadListener) {
            ((OnFirebaseStorageUploadListener) mContext).onUploadFailed();
        }
    }

    public interface OnFirebaseStorageUploadListener {
        void onUploadSucceed (String downloadUri);
        void onUploadFailed ();
    }

3.使用方法

MainActivity.java
public class MainActivity extends AppCompatActivity implements SimpleFirebaseStorageDatabase.OnFirebaseStorageUploadListener{

    private List<String> mUriList;

    @Override
    protected void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        SimpleFirebaseStorageDatabase firebaseStorage = new SimpleFirebaseStorageDatabase(ShareProjectActivity.this, mAuth, "バッケトトークン");
        mUriList = // ...
        firebaseStorage.uploadFilesByTempFile("ファイル名.zip", mUriList);
    }

    @Override
    public void onUploadSucceed (String downloadUri) {
        // 成功
    }

    @Override
    public void onUploadFailed () {
        // 失敗
    }

まとめ

今回は解説なしです。これに対応するダウンロードの処理は後日また書きます。
Firebaseを利用する際に必要になるログイン処理に関してはこちら
Twitter(フォローよろしくお願いします。): https://twitter.com/Cyber_Hacnosuke

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away