zoukankan      html  css  js  c++  java
  • 如何处理二进制文件?

    需求:
    wav是一种音频文件的格式,音频文件为二进制文件,wav文件由头部信息和音频采样数据组成,前44个字节为头部信息,包括声道数,采样频率,PCM位宽等等,后面是音频采样数据。
    使用python,分析一个wav文件头部信息,处理音频数据。

    思路:
    open函数想以二进制模式打开文件,指定Mode参数为'b'。
    二进制数据可以用readinto,读入提前分配的buffer中,便于数据处理。
    解析二进制数据可以使用标准库中的struct模块的unpack方法

    代码:

    import struct
    import array
    
    # 以rb的模式打开wav文件
    f = open('demo.wav','rb')
    
    # 读取前44个字节
    info = f.read(44)
    
    # 将文件的指针移到文件的末尾
    f.seek(0,2)
    
    # 报告文件的指针
    f.tell()
    
    # 计算数组的长度
    n = (f.tell() - 44) / 2
    
    # 生成数组并初始化数组
    buf = array.array('h',( 0 for _ in range(n)))
    
    # 将文件的数据读入到buf中
    # 首先要注意将文件的指针指向到data的开关
    f.seek(44)
    f.readinto(buf)
    
    # 对每一个采样数据进行除以8的操作,这样可以使wav文件的声音变小一些
    for i in range(n):
        buf[i] /= 8
    
    # 将改变的数据写入新的文件中
    f2 = open('demo2.wav','wb')
    # 先写入文件信息头的部分
    f2.write(info)
    # 将文件的数据写入文件中
    buf.tofile(f2)
    # 关闭文件
    f2.close()
    
    =========================================================================
    
    >>> f = open('demo.wav','rb')
    
    >>> info = f.read(44)
    
    >>> info
    b'RIFFx06xe5xfax01WAVELISTx98x00x00x00INFOIARTx05x00x00x00xd9xa9xd9xa9x00x00INAMx03x00'
    
    >>> type(info)
    bytes
    
    >>> info[22:24]
    b'FO'
    
    >>> import struct
    
    >>> struct.unpack('h',info[22:24])
    (20294,)
    
    >>> struct.unpack('>h',info[22:24])
    (17999,)
    
    >>> struct.unpack('>h',info[22:28])
    ---------------------------------------------------------------------------
    error                                     Traceback (most recent call last)
    <ipython-input-99-f44c391af760> in <module>
    ----> 1 struct.unpack('>h',info[22:28])
    
    error: unpack requires a buffer of 2 bytes
    
    >>> struct.unpack('i',info[24:28])
    (1414676809,)
    
    >>> info.find(b'data')
    -1
    
    >>> f.seek(0)
    0
    
    >>> f.read(100)
    b'RIFFx06xe5xfax01WAVELISTx98x00x00x00INFOIARTx05x00x00x00xd9xa9xd9xa9x00x00INAMx03x00x00x00xbbxadx00x00IPRDx07x00x00x00xd4xdaxd4xb6xb7xbdx00x00IGNRx05x00x00x00xc3xf1xd2xa5x00x00ITOCJx00x00x00C+96+404D+A8'
    
    >>> f.read(200)
    b'2E+FD6E+15732+19F7F+1D6AB+22FBF+27F40+2C3B9+32D7B+37FEC+3D049x00ITRKx02x00x00x006x00fmt x12x00x00x00x01x00x02x00Dxacx00x00x10xb1x02x00x04x00x10x00x00x00data@xe4xfax01x04x00xf4xffxfaxffx08x00x05x00xfcxffxfcxffx04x00x02x00xfaxffxffxffx07x00x03x00xfbxffxfdxffx08x00x06x00xfaxffxfaxffx05x00x02x00xf8xffx03x00x0cx00xfdxffxf3xffx01x00x0fx00x01x00xf4xffxffxff
    x00x04x00xf7xffxf7xffx0fx00
    x00xf0xffxf9xff	x00x06x00xfcxffxf8xffx05x00x00x00x00x00x00x00'
    
    >>> %load 5_2.py
    
    >>> # %load 5_2.py
    ... import struct
    ... 
    ... def find_subchunk(f.name):
    ...     f.seek(12)
    ...     while True:
    ...         chunk_name = f.read(4)
    ...         chunk_size, = struct.unpack('i',f.read(4))
    ... 
    ...         if chunk_name == name:
    ...             return f.tell(),chunk_size
    ... 
    ...         f.seek(chunk_size,1) # 1代表指针的当前点,0代表开关,2代表文件结尾,这里是表示指针往前跳chunk_size个距离
    ... 
    ... 
      File "<ipython-input-106-4d5fb97742fd>", line 4
        def find_subchunk(f.name):
                           ^
    SyntaxError: invalid syntax
    
    
    >>> 
    
    >>> %load 5_2.py
    
    >>> # %load 5_2.py
    ... import struct
    ... 
    ... def find_subchunk(f,name):
    ...     f.seek(12)
    ...     while True:
    ...         chunk_name = f.read(4)
    ...         chunk_size, = struct.unpack('i',f.read(4))
    ... 
    ...         if chunk_name == name:
    ...             return f.tell(),chunk_size  # 此处返回的是指针的偏移量和要查找块的大小
    ... 
    ...         f.seek(chunk_size,1) # 1代表指针的当前点,0代表开关,2代表文件结尾,这里是表示指针往前跳chunk_size个距离
    ... 
    ... 
    
    >>> f
    <_io.BufferedReader name='demo.wav'>
    
    >>> offset ,size = find_subchunk(f,b'data')  # 这里的数据前的部分不一定是44字节,需要定义一个函数来进行查找
    
    >>> offset
    206
    
    >>> size
    33219648
    
    >>> offset + size   # 可以看到和ll查看的大小是一致的
    33219854
    
    >>> ll demo.wav
    -rw-r--r-- 1 richardo 33219854 11月  3 15:42 demo.wav
    
    >>> import numpy as np
    ---------------------------------------------------------------------------
    ModuleNotFoundError                       Traceback (most recent call last)
    <ipython-input-115-0aa0b027fcb6> in <module>
    ----> 1 import numpy as np
    
    ModuleNotFoundError: No module named 'numpy'
    
    >>> import numpy as np
    
    >>> buffer = np.zeros(size//2,dtype=np.short)  # 生成一个buffer在bufer进行数据的处理
    
    >>> buf
    ---------------------------------------------------------------------------
    NameError                                 Traceback (most recent call last)
    <ipython-input-118-470933492c55> in <module>
    ----> 1 buf
    
    NameError: name 'buf' is not defined
    
    >>> buffer
    array([0, 0, 0, ..., 0, 0, 0], dtype=int16)
    
    >>> f.readinto(buffer)  # 将data的数据部分全部读入buffer中
    33219648
    
    >>>  buffer
    array([  4, -12,  -6, ...,  -2,  -6,   3], dtype=int16)
    
    >>> buffer[10000:20000]
    array([ 5, -3, -2, ..., -3, -6,  1], dtype=int16)
    
    >>> buffer //= 8  # 进行除以8处理,可以使文件的音量降低
    
    >>> f2 = open('out.wav','wb')
    
    >>> f.seek(0)
    0
    
    >>> info = f.read(offset)
    
    >>> f2.write(info)  # 先写data的前面头部部分
    206
    
    >>> buffer.tofile(f2)  # 再写data本身
    
    >>> f2.close()
    
    >>> 
    
    
  • 相关阅读:
    显示进度条
    LEAVE&nbsp;LIST-PROCESSING&nbsp;…
    博主心声
    sap设置权限
    快捷键大全
    VS快捷键
    vs中图片资源的横竖屏的影响
    error C4430: 缺少类型说明符
    cocos2dx3.3 使用cocos studio2.0 导出的.csb文件
    让cocos2d-x 3.0读取cocostudio中的csb文件
  • 原文地址:https://www.cnblogs.com/Richardo-M-Q/p/13290350.html
Copyright © 2011-2022 走看看