Example #1
0
        // 上传本地文件,或者删除服务器端文件
        // parameters:
        //      strStyle    当包含 delete 的时候,表示要删除 strFilePath 所指的文件
        // return:
        //      -2  时间戳不匹配
        //      -1  一般性错误
        //      0   成功
        //      其他  成功删除的文件和目录个数
        public int WriteFile(
            string strRootPath,
            string strFilePath,
            string strRanges,
            long lTotalLength,
            byte[] baSource,
            string strStyle,
            byte[] baInputTimestamp,
            out byte[] baOutputTimestamp,
            out string strError)
        {
            baOutputTimestamp = null;
            strError          = "";

            if (String.IsNullOrEmpty(strFilePath) == true)
            {
                strError = "strFilePath 参数值不能为空";
                return(-1);
            }
            if (lTotalLength < 0)
            {
                strError = "lTotalLength 参数值不能为负数";
                return(-1);
            }

            if (strStyle == null)
            {
                strStyle = "";
            }

            bool bDelete = StringUtil.IsInList("delete", strStyle) == true;

            if (bDelete == true)
            {
                int    nDeleteCount = 0;
                string strDirectory = Path.GetDirectoryName(strFilePath);
                string strPattern   = Path.GetFileName(strFilePath);

                DirectoryInfo    di  = new DirectoryInfo(strDirectory);
                FileSystemInfo[] sis = di.GetFileSystemInfos(strPattern);
                foreach (FileSystemInfo si in sis)
                {
                    // 安全性检查:不允许文件和目录越出指定的根目录
                    if (PathUtil.IsChildOrEqual(si.FullName, strRootPath) == false)
                    {
                        continue;
                    }

                    if (si is DirectoryInfo)
                    {
                        // 删除一个目录
                        _physicalFileCache.ClearAll();
                        PathUtil.DeleteDirectory(si.FullName);
                        nDeleteCount++;
                        continue;
                    }

                    if (si is FileInfo)
                    {
                        // 删除一个文件
                        //if (File.Exists(si.FullName) == true)
                        //    File.Delete(si.FullName);
                        _physicalFileCache.FileDeleteIfExists(si.FullName);

                        string strNewFilePath1 = GetNewFileName(si.FullName);

                        //if (File.Exists(strNewFilePath1) == true)
                        //    File.Delete(strNewFilePath1);
                        _physicalFileCache.FileDeleteIfExists(strNewFilePath1);

                        string strRangeFileName = GetRangeFileName(si.FullName);

                        //if (File.Exists(strRangeFileName) == true)
                        //    File.Delete(strRangeFileName);
                        _physicalFileCache.FileDeleteIfExists(strRangeFileName);

                        nDeleteCount++;
                    }
                }

                return(nDeleteCount);
            }
#if NO
            if (bDelete == true && Directory.Exists(strFilePath) == true)
            {
                // 删除一个目录
                PathUtil.DeleteDirectory(strFilePath);
                return(0);
            }

            string strNewFilePath = GetNewFileName(strFilePath);

            if (bDelete == true && File.Exists(strFilePath) == true)
            {
                // 删除一个文件
                if (File.Exists(strFilePath) == true)
                {
                    File.Delete(strFilePath);
                }

                if (File.Exists(strNewFilePath) == true)
                {
                    File.Delete(strNewFilePath);
                }

                string strRangeFileName = GetRangeFileName(strFilePath);

                if (File.Exists(strRangeFileName) == true)
                {
                    File.Delete(strRangeFileName);
                }

                return(0);
            }
#endif

            if (bDelete == false && baSource == null)
            {
                strError = "baSource 参数值不能为 null";
                return(-1);
            }

            string strNewFilePath = GetNewFileName(strFilePath);

            // 确保文件的路径所经过的所有子目录已经创建
            PathUtil.TryCreateDir(Path.GetDirectoryName(strFilePath));

            //*************************************************
            // 检查时间戳,当目标文件存在时
            if (File.Exists(strFilePath) == true ||
                File.Exists(strNewFilePath) == true)
            {
                if (StringUtil.IsInList("ignorechecktimestamp", strStyle) == false)
                {
                    if (File.Exists(strNewFilePath) == true)
                    {
                        baOutputTimestamp = FileUtil.GetFileTimestamp(strNewFilePath);
                    }
                    else
                    {
                        baOutputTimestamp = FileUtil.GetFileTimestamp(strFilePath);
                    }
                    if (ByteArray.Compare(baOutputTimestamp, baInputTimestamp) != 0)
                    {
                        strError = "时间戳不匹配";
                        return(-2);
                    }
                }
            }
            else
            {
                if (bDelete == true)
                {
                    string strRangeFileName = GetRangeFileName(strFilePath);

                    //if (File.Exists(strRangeFileName) == true)
                    //    File.Delete(strRangeFileName);
                    _physicalFileCache.FileDeleteIfExists(strRangeFileName);

                    return(0);
                }
                // 创建空文件
                _physicalFileCache.ClearItems(strFilePath);
                using (FileStream s = File.Create(strFilePath))
                {
                }
                baOutputTimestamp = FileUtil.GetFileTimestamp(strFilePath);
            }

#if NO
            // 删除文件
            if (bDelete == true)
            {
                if (File.Exists(strFilePath) == true)
                {
                    File.Delete(strFilePath);
                }

                if (File.Exists(strNewFilePath) == true)
                {
                    File.Delete(strNewFilePath);
                }

                string strRangeFileName = GetRangeFileName(strFilePath);

                if (File.Exists(strRangeFileName) == true)
                {
                    File.Delete(strRangeFileName);
                }

                return(0);
            }
#endif

            //**************************************************
            long lCurrentLength = 0;

            {
                if (baSource.Length == 0)
                {
                    if (strRanges != "")
                    {
                        strError = "当 baSource 参数的长度为 0 时,strRanges 的值却为 '" + strRanges + "',不匹配,此时 strRanges 的值应为空字符串";
                        return(-1);
                    }
                    // 把写到 metadata 里的尺寸设好
                    FileInfo fi = new FileInfo(strFilePath);
                    lCurrentLength = fi.Length;
                    fi             = null;
                }
            }

            //******************************************
            // 写数据
            if (string.IsNullOrEmpty(strRanges) == true)
            {
                if (lTotalLength > 0)
                {
                    strRanges = "0-" + Convert.ToString(lTotalLength - 1);
                }
                else
                {
                    strRanges = "";
                }
            }
            string strRealRanges = strRanges;

            // 检查本次传来的范围是否是完整的文件。
            bool bIsComplete = false;
            if (lTotalLength == 0)
            {
                bIsComplete = true;
            }
            else
            {
                //		-1	出错
                //		0	还有未覆盖的部分
                //		1	本次已经完全覆盖
                int nState = RangeList.MergeContentRangeString(strRanges,
                                                               "",
                                                               lTotalLength,
                                                               out strRealRanges,
                                                               out strError);
                if (nState == -1)
                {
                    strError = "MergeContentRangeString() error 1 : " + strError + " (strRanges='" + strRanges + "' lTotalLength=" + lTotalLength.ToString() + ")";
                    return(-1);
                }
                if (nState == 1)
                {
                    bIsComplete = true;
                }
            }

            if (bIsComplete == true)
            {
                if (baSource.Length != lTotalLength)
                {
                    strError = "范围 '" + strRanges + "' 与数据字节数组长度 '" + baSource.Length.ToString() + "' 不符合";
                    return(-1);
                }
            }

            RangeList rangeList = new RangeList(strRealRanges);

#if NO
            // 开始写数据
            Stream target = null;
            if (bIsComplete == true)
            {
                target = File.Create(strFilePath);  //一次性发完,直接写到文件
            }
            else
            {
                target = File.Open(strNewFilePath, FileMode.OpenOrCreate);
            }
            try
            {
                int nStartOfBuffer = 0;
                for (int i = 0; i < rangeList.Count; i++)
                {
                    RangeItem range = (RangeItem)rangeList[i];
                    // int nStartOfTarget = (int)range.lStart;
                    int nLength = (int)range.lLength;
                    if (nLength == 0)
                    {
                        continue;
                    }

                    Debug.Assert(range.lStart >= 0, "");

                    // 移动目标流的指针到指定位置
                    target.Seek(range.lStart,
                                SeekOrigin.Begin);

                    target.Write(baSource,
                                 nStartOfBuffer,
                                 nLength);

                    nStartOfBuffer += nLength;
                }
            }
            finally
            {
                target.Close();
            }
#endif

            // 开始写数据
            StreamItem target = null;
            if (bIsComplete == true)
            {
                target = _physicalFileCache.GetStream(strFilePath, FileMode.Create, FileAccess.Write, false);  //一次性发完,直接写到文件
            }
            else
            {
                target = _physicalFileCache.GetStream(strNewFilePath, FileMode.OpenOrCreate, FileAccess.Write);
            }
            try
            {
                int nStartOfBuffer = 0;
                for (int i = 0; i < rangeList.Count; i++)
                {
                    RangeItem range = (RangeItem)rangeList[i];
                    // int nStartOfTarget = (int)range.lStart;
                    int nLength = (int)range.lLength;
                    if (nLength == 0)
                    {
                        continue;
                    }

                    Debug.Assert(range.lStart >= 0, "");

                    // 移动目标流的指针到指定位置
                    target.FileStream.FastSeek(range.lStart);

                    target.FileStream.Write(baSource,
                                            nStartOfBuffer,
                                            nLength);

                    nStartOfBuffer += nLength;
                }
            }
            finally
            {
                _physicalFileCache.ReturnStream(target);
            }

            {
                string strRangeFileName = GetRangeFileName(strFilePath);

                // 如果一次性写满的情况,需要做下列几件事情:
                // 1.时间戳以目标文件计算
                // 2.写到metadata的长度为目标文件总长度
                // 3.如果存在临时辅助文件,则删除这些文件。

                // 4. 设置目标文件的 LastWriteTime
                if (bIsComplete == true)
                {
                    // baOutputTimestamp = CreateTimestampForCfg(strFilePath);
                    lCurrentLength = lTotalLength;

                    // 删除辅助文件
                    //if (File.Exists(strNewFilePath) == true)
                    //    File.Delete(strNewFilePath);
                    _physicalFileCache.FileDeleteIfExists(strNewFilePath);

                    //if (File.Exists(strRangeFileName) == true)
                    //    File.Delete(strRangeFileName);
                    _physicalFileCache.FileDeleteIfExists(strRangeFileName);

                    goto END1;
                }


                //****************************************
                //处理辅助文件
                bool   bEndWrite      = false; // 是否为最后一次写入操作
                string strResultRange = "";
                if (strRanges == "" || strRanges == null)
                {
                    bEndWrite = true;
                }
                else
                {
                    string strOldRanges = "";

                    if (IsFirstRange(strRanges, lTotalLength, out bEndWrite) == false)
                    {
                        if (File.Exists(strRangeFileName) == true)
                        {
                            string strText           = FileUtil.File2StringE(strRangeFileName);
                            string strOldTotalLength = "";
                            StringUtil.ParseTwoPart(strText, "|", out strOldRanges, out strOldTotalLength);
                        }
                        // return
                        //		-1	出错
                        //		0	还有未覆盖的部分
                        //		1	本次已经完全覆盖
                        int nState1 = RangeList.MergeContentRangeString(strRanges,
                                                                        strOldRanges,
                                                                        lTotalLength,
                                                                        out strResultRange,
                                                                        out strError);
                        if (nState1 == -1)
                        {
                            strError = "MergeContentRangeString() error 2 : " + strError + " (strRanges='" + strRanges + "' strOldRanges='" + strOldRanges + "' ) lTotalLength=" + lTotalLength.ToString() + "";
                            return(-1);
                        }
                        if (nState1 == 1)
                        {
                            bEndWrite = true;
                        }
                    }
                    else
                    {
                        strResultRange = strRanges;
                    }
                }

                // 如果文件已满,需要做下列几件事情:
                // 1.按最大长度截临时文件
                // 2.将临时文件拷到目标文件
                // 3.删除new,range辅助文件
                // 4.时间戳以目标文件计算
                // 5.metadata的长度为目标文件的总长度

                // 6. 设置目标文件的 LastWriteTime
                if (bEndWrite == true)
                {
                    _physicalFileCache.ClearItems(strNewFilePath);

                    using (Stream s = new FileStream(strNewFilePath,
                                                     FileMode.OpenOrCreate))
                    {
                        s.SetLength(lTotalLength);
                    }

                    // TODO: Move 文件较好。改名

                    //File.Delete(strFilePath);
                    //File.Move(strNewFilePath, strFilePath);
                    this._physicalFileCache.FileDelete(strFilePath);
                    this._physicalFileCache.FileMove(strNewFilePath, strFilePath);

                    //if (File.Exists(strRangeFileName) == true)
                    //    File.Delete(strRangeFileName);
                    _physicalFileCache.FileDeleteIfExists(strRangeFileName);

                    baOutputTimestamp = FileUtil.GetFileTimestamp(strFilePath);

                    lCurrentLength = lTotalLength;

                    bIsComplete = true;
                }
                else
                {
                    //如果文件未满,需要做下列几件事情:
                    // 1.把目前的range写到range辅助文件
                    // 2.时间戳以临时文件计算
                    // 3.metadata的长度为-1,即未知的情况
                    FileUtil.String2File(strResultRange + "|" + lTotalLength.ToString(),
                                         strRangeFileName);

                    lCurrentLength = -1;

                    baOutputTimestamp = FileUtil.GetFileTimestamp(strNewFilePath);
                }
            }

END1:
            if (bIsComplete == true)
            {
                // 多轮上传的内容完成后,最后需要单独设置文件最后修改时间
                string strLastWriteTime = StringUtil.GetStyleParam(strStyle, "last_write_time");
                // parameters:
                //      baTimeStamp 8 byte 的表示 ticks 的文件最后修改时间。应该是 GMT 时间
                FileUtil.SetFileLastWriteTimeByTimestamp(strFilePath, ByteArray.GetTimeStampByteArray(strLastWriteTime));
                baOutputTimestamp = FileUtil.GetFileTimestamp(strFilePath);

                // 结束时自动展开一个压缩文件
                if (StringUtil.IsInList("extractzip", strStyle) == true)
                {
                    try
                    {
                        ReadOptions option = new ReadOptions();
                        option.Encoding = Encoding.UTF8;
                        _physicalFileCache.ClearItems(strFilePath);
                        using (ZipFile zip = ZipFile.Read(strFilePath, option))
                        {
                            foreach (ZipEntry e in zip)
                            {
                                string strTargetDir = Path.GetDirectoryName(strFilePath);
                                e.Extract(strTargetDir, ExtractExistingFileAction.OverwriteSilently);
                                // 2017/4/8 修正文件最后修改时间
                                string strFullPath = Path.Combine(strTargetDir, e.FileName);
                                if ((e.Attributes & FileAttributes.Directory) == 0)
                                {
                                    if (e.LastModified != File.GetLastWriteTime(strFullPath))
                                    {
                                        // 时间有可能不一致,可能是夏令时之类的问题
                                        File.SetLastWriteTime(strFullPath, e.LastModified);
                                    }
                                    Debug.Assert(e.LastModified == File.GetLastWriteTime(strFullPath));
                                }
                            }
                        }

                        File.Delete(strFilePath);
                    }
                    catch (Exception ex)
                    {
                        strError = ExceptionUtil.GetAutoText(ex);
                        return(-1);
                    }
                }
            }

            return(0);
        }