def save(self, filething=None):
        """Save changes to a file.

        If no filename is given, the one most recently loaded is used.

        Tags are always written at the end of the file, and include
        a header and a footer.
        """

        fileobj = filething.fileobj

        data = _APEv2Data(fileobj)

        if data.is_at_start:
            delete_bytes(fileobj, data.end - data.start, data.start)
        elif data.start is not None:
            fileobj.seek(data.start)
            # Delete an ID3v1 tag if present, too.
            fileobj.truncate()
        fileobj.seek(0, 2)

        tags = []
        for key, value in self.items():
            # Packed format for an item:
            # 4B: Value length
            # 4B: Value type
            # Key name
            # 1B: Null
            # Key value
            value_data = value._write()
            if not isinstance(key, bytes):
                key = key.encode("utf-8")
            tag_data = bytearray()
            tag_data += struct.pack("<2I", len(value_data), value.kind << 1)
            tag_data += key + b"\0" + value_data
            tags.append(bytes(tag_data))

        # "APE tags items should be sorted ascending by size... This is
        # not a MUST, but STRONGLY recommended. Actually the items should
        # be sorted by importance/byte, but this is not feasible."
        tags.sort(key=lambda tag: (len(tag), tag))
        num_tags = len(tags)
        tags = b"".join(tags)

        header = bytearray(b"APETAGEX")
        # version, tag size, item count, flags
        header += struct.pack("<4I", 2000, len(tags) + 32, num_tags,
                              HAS_HEADER | IS_HEADER)
        header += b"\0" * 8
        fileobj.write(header)

        fileobj.write(tags)

        footer = bytearray(b"APETAGEX")
        footer += struct.pack("<4I", 2000, len(tags) + 32, num_tags,
                              HAS_HEADER)
        footer += b"\0" * 8

        fileobj.write(footer)
def save ( self , filething = None ) : fileobj = filething . fileobj data = _APEv2Data ( fileobj ) if data . is_at_start : delete_bytes ( fileobj , data . end - data . start , data . start ) elif data . start is not None : fileobj . seek ( data . start ) fileobj . truncate ( ) fileobj . seek ( 0 , 2 ) tags = [ ] for key , value in self . items ( ) : value_data = value . _write ( ) if not isinstance ( key , bytes ) : key = key . encode ( "utf-8" ) tag_data = bytearray ( ) tag_data += struct . pack ( "<2I" , len ( value_data ) , value . kind << 1 ) tag_data += key + b"\0" + value_data tags . append ( bytes ( tag_data ) ) tags . sort ( key = lambda tag : ( len ( tag ) , tag ) ) num_tags = len ( tags ) tags = b"" . join ( tags ) header = bytearray ( b"APETAGEX" ) header += struct . pack ( "<4I" , 2000 , len ( tags ) + 32 , num_tags , HAS_HEADER | IS_HEADER ) header += b"\0" * 8 fileobj . write ( header ) fileobj . write ( tags ) footer = bytearray ( b"APETAGEX" ) footer += struct . pack ( "<4I" , 2000 , len ( tags ) + 32 , num_tags , HAS_HEADER ) footer += b"\0" * 8 fileobj . write ( footer )
Save changes to a file.

        If no filename is given, the one most recently loaded is used.

        Tags are always written at the end of the file, and include
        a header and a footer.