Java传递音频给PC端C#程序(1)

需求

把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压缩。如果还是较大,可以分段传输。

缺点

这种传递文件的做法不推荐,因为传递10M以上的文件极有可能OOM,因为Java虚拟机顶不住。

改进

请看第二篇文章Java传递音频给PC端C#程序(2)

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

喝水不忘挖井人

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,567评论 18 399
  • 编码问题一直困扰着开发人员,尤其在 Java 中更加明显,因为 Java 是跨平台语言,不同平台之间编码之间的切换...
    x360阅读 2,463评论 1 20
  • tags:io categories:总结 date: 2017-03-28 22:49:50 不仅仅在JAVA领...
    行径行阅读 2,168评论 0 3
  • 我希望,将来我结婚了,是因为爱情,而不是因为条件合适或为了繁衍后代。在我看来,感情真的比物质重要很多,感情是点滴的...
    文艺小呆阅读 263评论 0 0
  • 28/100 #100天坚持一件事# 星期三 雨 早起6:00 早餐:小米红枣粥 今日背诵经文: 弟兄们,在心...
    zuimeideni阅读 351评论 0 0