Java传递音频给PC端C#程序<一>
来源:互联网 发布:如何入驻天猫淘宝商城 编辑:程序博客网 时间:2024/06/02 12:02
需求
把Android手机的mp3文件以TCP的传输方式传递到Win10的C#程序上,并且附带歌名等信息。
PC端的要求是传递一个序列化后的文件过去,里面包含了文件本体和文件名等信息。
该序列化(C#这里的序列化好像和Java里面相差甚大啊!起初我是一头雾水的)后的文件格式如下:
( ⊙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编码成字符串进行保存或传输
- Java传递音频给PC端C#程序<一>
- Java传递音频给PC端C#程序<一>
- Java传递音频给PC端C#程序<二>
- c++程序启动一个C#程序,并给C#程序传递参数,程序间实现参数传递
- java程序用post方式给某一网页传递参数
- C# 给线程传递数据
- c#传递数组给函数
- Unity 打包pc端.exe C#防止多个程序
- flex传递对象给java
- flex传递对象给java
- JAVA给方法传递数组
- jni传递数据给java
- 判断延迟搜索的程序,例如:给pc端的及时搜索用
- c#给线程传递参数的方法
- C# 传递图片给C++dll
- Python中传递参数给程序
- 使用Pycharm给Python程序传递参数
- Java给Main函数传递参数
- Minimum Window Substring
- CSU 1831 Found(ACM-ICPC Asia Thailand National On-Site Programming Contest 2015)
- Unity实现标准光照模型的Shader代码
- SymPy学习之Elementary
- SymPy学习之Geometry Module
- Java传递音频给PC端C#程序<一>
- Java温习——面向对象第三部分
- VPN篇(5.4) 01. SSL VPN
- JAVA日期类求年龄并求出大于指定年龄的学生。本人菜鸟,第一次发JAVA博客,也是第一次发博客!望大家交流指正!
- Lambda&Java多核编程-5-函数式接口与function包
- 【Mybatis】 JdbcType 与 JavaType对应关系
- C++:进程间通讯(部分转载,个人整理)
- Java基于JavaMail实现向QQ邮箱发送邮件
- Jekyll搭建lanmps.com站点