cycles adding texture to face via python / import script
For materials, this is simple: each polygon (face) as a "material_index" property which corresponds to the object's "material_slots" property.

For the UVs, that can be more complex. Here is how Blender stores all that:

UV layers are in "obj.data.uv_layers". 

But to create uv layers, you need to go to "uv_textures" and add one via "obj.data.uv_textures.new( 'name' )".

You can now access to "obj.data.uv_layers['name']" and to "obj.data.uv_layers['name'].data". This last data is an array that contains information for each vertex in the mean of uv layer vertex (not 3D vertex, because a 3D vertex can be represented many times in the UV map).

What is unifying all these is the concept of 'loop'. 'loop' is a per face information.

You have a 'main loop' which is into "obj.data.loops" and contains the 3D per face information for each vertex. Say we take "loop_info = obj.data.loops[0]", it contains "loop_info.vertex_index" (the index to find the 3D vertex in "obj.data.vertices"), and other information like vertex "normal".

Now an uv layers is also a per face information (a loop). "obj.data.uv_layers['name'].data" is a loop (organized with the same index order as the main loop).

If we take "uv_info = obj.data.uv_layers['name'].data[0]", "uv_info.uv" is the 2D coordinate in this UV map.

Last thing you need to know (I think), the correspondence between a polygon and the loops: this is stored in the polygon itself. If you get "polygon = obj.data.polygons[0]", then you can get the loop projection of its vertices in "polygon.loop_indices". 

For instance, "obj.data.uv_layers['name'].data[polygon.loop_indices[0]]" is valid.

I think the other aspects are relative to your file format.

Concerning images. You can start with "img = bpy.data.images.new(name, width, height)". Color information is in "img.pixels" organized from bottom left to upper right (UV like). "img.pixels" is a 4*width*height float array containing R,G,B,A values (black is 0, white is 1).

Following the comments... I cannot imagine what your file format is.

So I can only, give some advices and a little help...

Warning this code is untested (as I have no data), so surely, there will be some bugs here. But I hope that will help for the principles of how it works:

Materials part: just for the comment at the end

modelName = "xxxx"
mesh = bpy.data.meshes.new( modelName )
obj = bpy.data.objects.new( modelName, mesh )

for textures in range(0, MtlCount):
    StrLen = struct.unpack('i',fdata.read(4))[0]

    mtlname = fdata.read(StrLen).decode()

    MyTextureNames.append( mtlname )

    new_mat = bpy.data.materials.new( mtlname )
    new_mat.use_nodes = True

    #I do prefer using .data instead of .ops because ops often need a context and/or a mode
    obj.data.materials.append( new_mat )


Creating the mesh, with some guess about unpack (as I've never used it).
But that should work and be faster than a for loop.

def ToTuples( aList, tupleSize ):
    return [tuple(aList[x:x+tupleSize]) for x in range(0, len(aList), tupleSize)]

#Shorter... probably much faster than loops
myVertices = ToTuples( struct.unpack( 'f', fdata.read( 4 * 3 * VertexCount ) ), 3 )
myFaces = ToTuples( struct.unpack( 'i', fdata.read( 4 * 3 * FaceCount ) ), 3 )

mesh.from_pydata( myVertices, [], myfaces )
mesh.update()


Face material attribution: 2 examples

#If face/material is describe as face index to material index in your file
for fIndex, mIndex in ToTuples( struct.unpack( 'i', fdata.read( 4 * 2 * FaceCount ) ), 2 ):
    mesh.polygons[fIndex].materialIndex = mIndex

#If face/material is describe just as a sequence of material index in the same order as the faces
for fIndex, mIndex in enumerate( struct.unpack( 'i', fdata.read( 4 * FaceCount ) ) ):
    mesh.polygons[fIndex].materialIndex = mIndex


UV map:

#Assuming you have one UV map and all polygons are tris
#=&gt; you have 3 * FaceCount uv definitions in Blender, so this is the size of the 'loop(s)'
#But I do not know how your file is...
#So, I guess it is defined as the following, assuming the vertex order of the face is the same as above:
# faceIndex, vertex1co, vertex2co, vertex3co
# All these is 7 * 4 bytes * FaceCount

uvTex = mesh.uv_textures.new()
uvMap = mesh.uv_layers[uvTex.name]

for fi, v1x, v1y, v2x, v2y, v3x, v3y in ToTuples( struct.unpack( 'i f f f f f f', fdata.read( 7 * 4 * FaceCount ) ), 7 ):
    #Find the polygon
    polygon = mesh.polygons[fi]
    #In the uv map, get the corresponding vertex using the polygon loop index (for first, second and third) and set its uv coordinates
    uvMap.data[polygon.loop_indices[0]].uv = (v1x, v1y)
    uvMap.data[polygon.loop_indices[1]].uv = (v2x, v2y)
    uvMap.data[polygon.loop_indices[2]].uv = (v3x, v3y)


I don't think this is the place to do more... and doing more needs to know the specifications of your file format...

Hope it helps!