Java传递音频给PC端C#程序<一>

来源:互联网 发布:如何入驻天猫淘宝商城 编辑:程序博客网 时间:2024/06/02 12:02

需求

把Android手机的mp3文件以TCP的传输方式传递到Win10的C#程序上,并且附带歌名等信息。
PC端的要求是传递一个序列化后的文件过去,里面包含了文件本体和文件名等信息。
该序列化(C#这里的序列化好像和Java里面相差甚大啊!起初我是一头雾水的)后的文件格式如下:


QQ图片20170317130027.png

( ⊙o⊙ )? 什么鬼,没办法硬着头皮试,起初根本不知道这是什么码,因为在Android里,传递文件最底层的就是字节流,那这个又是什么编码呢。

尝试

方式有很多种,比如把所有信息转成字节传递过去,但是告知对方在哪里是什么,这种很麻烦;把文件转成byte[]后放入一个类中,该类携带歌曲信息以byte[]发送过去。
尝试了几种方法:

1、 第一次(失败)

ObjectOutputSteam object = new ObjectOutputStream(socket.getOutputStream());

通过对象流发送,发送过去后直接乱码了,不用说,肯定是不能通过这样的方式发送了,因为对象流是JVM之间的一种传递方式,把对象以这种方式传递明显行不通。

2、 第二次(失败)

直接利用文件流把文件转成byte[]然后传递过去,但是这种传递没有办法传递歌曲信息,尝试用类来包裹

byte[] musicBytes = getBytes(filePath);//歌曲文件的字节数组SimpleMusicEntity simpleMusicEntity = new SimpleMusicEntity();simpleMusicEntity.setMusicBytes(musicBytes);simpleMusicEntity.setTitle(title);
    /**     * 获得指定文件的byte数组     */    public static byte[] getBytes(String filePath) {        byte[] buffer = null;        try {            File file = new File(filePath);            FileInputStream fis = new FileInputStream(file);            ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);            byte[] b = new byte[1024];            int n;            while ((n = fis.read(b)) != -1) {                bos.write(b, 0, n);            }            fis.close();            bos.close();            buffer = bos.toByteArray();        } catch (IOException e) {            e.printStackTrace();        }        return buffer;    }

so,问题来了,我得到了一个类SimpleMusicEntity,里面富含了歌曲的所有信息(名称、ext、文件字节),怎么传呢。
用Gson转对象为Json传递过去,成功了!就这么的,我测试了传递一曲“滴滴滴.mp3”成功了,对方从其中拿到byte[]数组转文件也能播放成功。继续测试,传一首歌曲,直接OOM!错误大概是消耗了几十兆的空间导致App直接crash。

为什么呢,显而易见,因为字符串太长了!你把一个歌曲转换成byte[]然后再转换成String,你知道这个String.length()有多长么,不说了高兴太早。

3、第三次

找了半天终于知道有这么一个东西“Base64”!
目前的做法是File转byte[],byte[]通过转为Base64的字符串,这样得到的文件大小比原文件大1.2倍左右(拿首歌曲测试)

        byte[] musicBytes = getBytes(filePath);//歌曲文件的字节数组        String str = new String(Base64.encode(musicBytes, Base64.NO_WRAP ));        SimpleMusicEntity2 simpleMusicEntity2 = new SimpleMusicEntity2();        simpleMusicEntity2.setMusicBytes(str);        simpleMusicEntity2.setTitle(title);        String string =simpleMusicEntity2.toString;
public class SimpleMusicEntity2{    private String title;    private String musicBytes;    //构造一个json字符串    @Override    public String toString() {        return "{"                + "\"title\":"                + "\"" + title + '\"'                + ","                + "\"musicBytes\":"                + "\"" + musicBytes + '\"' +                '}'+                "\r\n"                ;    }}

Base64简单说一下

上面第二行“Base64.NO_WRAP”
为什么要用这个,因为如果用Base64.DEFAULT的话,我们的string里会自动添加换行符“\n”

flag常量

Base64.CRLF 这个参数意思是Win风格的换行符,意思就是使用CR LF这一对作为一行的结尾而不是Unix风格的LF
Base64.DEFAULT 这个参数是默认,使用默认的方法来加密
Base64.NO_PADDING 这个参数是略去加密字符串最后的”=”
Base64.NO_WRAP 这个参数意思是略去所有的换行符(设置后CRLF就没用了)
Base64.URL_SAFE 这个参数意思是加密时不使用对URL和文件名有特殊意义的字符来作为加密字符,具体就是以-和_取代+和/
//习惯上使用Base64.NO_WRAP,使用什么方式编码就需要使用什么方式解码。

Base64Api

//将字节数组编码,返回为String
Base64.encodeToString(byte[] bs,int flag);
//将字节数组编码,返回字节数组
Base64.encode(byte[] bs,int flag);
//将字节数组按指定位置部分编码,返回字符串
Base64.encodeToString(byte[] bs,int offset,int lenth);
//将字节数组按指定位置部分编码,返回字节数组
Base64.encode(byte[] bs,int offset,int lenth);
//将编码后的字符串解码返回字节数组
Base64.decode(String str,int flag);
//将编码后的字节数组解码返回字节数组
Base64.decode(byte[],int flag);
//将编码后的字节数组按指定位置部分解码,返回字节数组
Base64.decode(byte[] bs,int offset,int len);

最后

发送方式,下面两种方式都行:

        byte[] bytes = string.getBytes();        //byte[] enter = "\r\n".getBytes();//这个换行符必须写在字符串末端,不能单独发送换行符        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));        dos.write(bytes);        //dos.write(enter);        dos.flush();        dos.close();
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));        bufferedWriter.write(string);        bufferedWriter.flush();        bufferedWriter.close();

终于PC端的C#程序能接收到文件信息,也能正确播放了,并且也有歌曲名字。

如果文件较大,可以先zip压缩。如果还是较大,可以分段传输。

缺点:这样做Android端只能传递大概10M的文件,后来更改写法使用类似报头的方式传输字节流,解决了文件过大问题。

这只是功能demo而已,其实Android还要考虑很多,比如ip是变化的,我怎么获取对应设备的ip,然后建立TCP连接等等。

喝水不忘挖井人

参考文献:
Android编码解码及其原理
文件与base64二进制转换
图片与Base64相互转换,c#与java通用
Byte[]和BASE64之间的转换
对文件进行base64编码成字符串进行保存或传输


0 0
原创粉丝点击