iOS大文件斷點(diǎn)下載

廢話不多所,直接上代碼
github網(wǎng)址:https://github.com/SPStore/SPHTTPSessionManager

.h文件

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

typedef NS_ENUM(NSInteger, SPDownloadWay) {
    SPDownloadWayResume,    // 這種下載方式支持重啟app時(shí)繼續(xù)上一次的下載
    SPDownloadWayRestart    // 這種下載方式不支持重啟app時(shí)繼續(xù)上一次的下載
    
    // SPDownloadWayResume和SPDownloadWayRestart的下載方式具體異同點(diǎn)如下:
    /*
    1、SPDownloadWayResume和SPDownloadWayRestart均支持?jǐn)帱c(diǎn)下載
    2、SPDownloadWayResume支持重啟app繼續(xù)上一次下載,SPDownloadWayRestart不支持
    3、SPDownloadWayResume會(huì)自動(dòng)判斷是否下載完成,并保存每時(shí)每刻下載的進(jìn)度值,SPDownloadWayRestart沒(méi)有此功能
    4、SPDownloadWayResume支持任何時(shí)刻刪除已經(jīng)下載的文件數(shù)據(jù),SPDownloadWayRestart不支持在下載過(guò)程中刪除,只有下載完成時(shí)才能刪除
    5、SPDownloadWayResume不依賴于AFN,SPDownloadWayRestart依賴AFN
     
     通俗的講,SPDownloadWayResume和SPDownloadWayRestart的根本區(qū)別就是前者是沙盒模式,后者是內(nèi)存模式
     */
    
};

NS_ASSUME_NONNULL_BEGIN
@interface SPHTTPSessionManager : NSObject

/** 單例對(duì)象 */
+ (instancetype)shareInstance;

/**
 *  get請(qǐng)求
 *
 *  @param urlString 請(qǐng)求地址
 *  @param params    參數(shù)字典
 *  @param success   請(qǐng)求成功回調(diào)的block
 *  @param failure   請(qǐng)求失敗回調(diào)的block
 */
- (void)GET:(NSString *)urlString
     params:(NSDictionary *)params
    success:(void (^)(id responseObject))success
    failure:(void (^)(NSError *error))failure;

/**
 *  post請(qǐng)求
 *
 *  @param urlString 請(qǐng)求地址
 *  @param params    參數(shù)字典
 *  @param success   請(qǐng)求成功回調(diào)的block
 *  @param failure   請(qǐng)求失敗回調(diào)的block
 */
- (void)POST:(NSString *)urlString
      params:(NSDictionary *)params
     success:(void (^)(id responseObject))success
     failure:(void (^)(NSError *error))failure;

/**
 *  下載
 *
 *  @param urlString 請(qǐng)求地址
 *  @param downloadProgressBlock  下載過(guò)程中回調(diào)的block
 *  @complete 下載完成回調(diào)的block
 */
- (NSURLSessionTask *)downloadWithURL:(NSString *)urlString
                                     progress:(void (^)(CGFloat progress))downloadProgressBlock
                                     complete:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler;


/*
 * 上傳  http://www.cnblogs.com/qingche/p/5489434.html
 *
 */
- (void)uploadWithURL:(NSString *)urlString
               params:(NSDictionary *)params
             fileData:(NSData *)filedata
                 name:(NSString *)name
             fileName:(NSString *)filename
             mimeType:(NSString *) mimeType
             progress:(void (^)(NSProgress *uploadProgress))uploadProgressBlock
              success:(void (^)(id responseObject))success
              failure:(void (^)(NSError *error))failure;

// 以下這些操作在外界也可以另外做到,比如啟動(dòng)和暫停任務(wù),外界在調(diào)用下載的方法時(shí)返回了一個(gè)task,開(kāi)發(fā)者可以用該task去啟動(dòng)和暫停任務(wù),之所以將其封裝,一是:這個(gè)類能做到的盡量不讓開(kāi)發(fā)者去做,二是:讓開(kāi)發(fā)者完全面向我這個(gè)單例對(duì)象。開(kāi)發(fā)者只需要做一些關(guān)于UI的事情

// 下載方式
@property (nonatomic, assign) SPDownloadWay downloadway;

/*
 *  啟動(dòng)任務(wù)
 *
 */
- (void)resumeTask;
/* 
 *  暫停任務(wù)
 *
 */
- (void)suspendTask;
/*
 *  取消任務(wù)
 *
 */
- (void)cancelTask;

/*
 *  移除已經(jīng)下載好的文件數(shù)據(jù) 
 *
 */
- (BOOL)removeDownloadedData:(NSError * _Nullable __autoreleasing * _Nullable)error;

/** 是否正在下載,對(duì)于SPDownloadResume下載方式,該屬性來(lái)源于沙盒,對(duì)于SPDownloadRestart下載方式,該屬性來(lái)源于內(nèi)存 */
@property (nonatomic, assign, readonly, getter=isDownloading) BOOL downloading;


// 以下兩個(gè)屬性只對(duì)SPDownloadResume下載方式奏效

/** 保存在沙盒中的進(jìn)度值 */
@property (nonatomic, assign, readonly) CGFloat storedDownloadProgress;
/** 是否已經(jīng)下載完畢 */
@property (nonatomic, assign, readonly, getter=isDownloadCompleted) BOOL downloadCompleted;

@end
NS_ASSUME_NONNULL_END


@interface NSString (MD5)

@property (nullable, nonatomic, readonly) NSString *md5String;

@end

.m文件

#import "SPHTTPSessionManager.h"
#import "AFNetworking.h"

// 文件名,MD5加密
#define SPFileName self.fileURLString.md5String

// 文件的存放路徑(caches)
#define SPFileFullPath [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:SPFileName]

// 存儲(chǔ)文件信息的路徑(caches)
#define SPFileInfoPath [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"sp_fileInfo.info"]

// 文件的已下載長(zhǎng)度
#define SPDownloadLength [[[NSFileManager defaultManager] attributesOfItemAtPath:SPFileFullPath error:nil][NSFileSize] integerValue]

@interface SPHTTPSessionManager() <NSURLSessionDelegate> {
    CGFloat _storedDownloadProgress;
    BOOL _downloadCompleted;
    BOOL _downloading;
}
/** session */
@property (nonatomic, strong) NSURLSession *session;
/** 寫(xiě)文件的流對(duì)象 */
@property (nonatomic, strong) NSOutputStream *stream;
/** 文件的總長(zhǎng)度 */
@property (nonatomic, assign) NSInteger totalLength;
/** 下載任務(wù) */
@property (nonatomic, strong) NSURLSessionTask *task;
/** 文件的url */
@property (nonatomic, strong) NSString *fileURLString;
/** 下載過(guò)程中回調(diào)的block */
@property (nonatomic, copy) void (^downloadProgressBlock)(CGFloat progress);
/** 下載完成回調(diào)的block */
@property (nonatomic,copy) void (^completionHandler)(NSURLResponse *response, NSURL *URL, NSError *error);
/** 存儲(chǔ)文件信息的字典,該字典要寫(xiě)入沙盒 */
@property (nonatomic, strong) NSMutableDictionary *fileInfoDictionry;

// ------------ 上面的額屬性是針對(duì)下載2,下面的屬性針對(duì)下載1 -------------
/** 下載1的文件url地址 */
@property (nonatomic, copy) NSString *downloadFromZero_UrlString;
/** 下載1完成后保存的文件路徑 */
@property (nonatomic, copy) NSString *downloadFromZero_filePath;
/** 下載1過(guò)程中回調(diào)的block */
@property (nonatomic, copy) void (^downloadFromZero_ProgressBlock)(CGFloat progress);
/** 下載1完成回調(diào)的block */
@property (nonatomic,copy) void (^downloadFromZero_completionHandler)(NSURLResponse *response, NSURL *URL, NSError *error);

@end

@implementation SPHTTPSessionManager

+ (instancetype)shareInstance {
    static SPHTTPSessionManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc] init];
    });
    return manager;
}


// get請(qǐng)求
- (void)GET:(NSString *)urlString params:(NSDictionary *)params
   success:(void (^)(id responseObject))success
   failure:(void (^)(NSError *error))failure {
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain",@"application/json",@"text/json",@"text/javascript",@"text/html", nil];
    
    [manager GET:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (failure) {
            failure(error);
        };
    }];
}

// post請(qǐng)求
- (void)POST:(NSString *)urlString params:(NSDictionary *)params
    success:(void (^)(id responseObject))success failure:(void (^)(NSError *error))failure{
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain",@"application/json",@"text/json",@"text/javascript",@"text/html", nil];
    
    [manager POST:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (failure) {
            failure(error);
        }
    }];
    
}

// 下載1(重啟app時(shí)從0開(kāi)始開(kāi)始)
- (NSURLSessionTask *)downloadFromZeroWithURL:(NSString *)urlString
                                     progress:(void (^)(CGFloat))downloadProgressBlock
                                     complete:(void (^)(NSURLResponse *, NSURL *, NSError *))completionHandler {
    
    self.downloadFromZero_UrlString = urlString;
    self.downloadFromZero_ProgressBlock = downloadProgressBlock;
    self.downloadFromZero_completionHandler = completionHandler;
  
    return self.task;
}

// 下載2(重啟app時(shí)從上一次的數(shù)據(jù)開(kāi)始)
- (NSURLSessionTask *)downloadWithURL:(NSString *)urlString
                                                   progress:(void (^)(CGFloat))downloadProgressBlock
                                                   complete:(void (^)(NSURLResponse *, NSURL *, NSError *))completionHandler {
    if (self.downloadway == SPDownloadWayResume) {
        self.fileURLString = urlString;
        
        // 將block參數(shù)賦值給全局block變量
        self.downloadProgressBlock = downloadProgressBlock;
        self.completionHandler = completionHandler;
        
        [self downloadFromZeroWithURL:urlString progress:downloadProgressBlock complete:completionHandler];
        
        return self.task;
    } else {
        return [self downloadFromZeroWithURL:urlString progress:downloadProgressBlock complete:completionHandler];
    }
}


// 上傳
- (void)uploadWithURL:(NSString *)urlString
              params:(NSDictionary *)params
            fileData:(NSData *)filedata
                name:(NSString *)name
            fileName:(NSString *)filename
            mimeType:(NSString *) mimeType
            progress:(void (^)(NSProgress *uploadProgress))uploadProgressBlock
             success:(void (^)(id responseObject))success
             failure:(void (^)(NSError *error))failure {
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    [manager POST:urlString parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        
        [formData appendPartWithFileData:filedata name:name fileName:filename mimeType:mimeType];
        
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        if (uploadProgressBlock) {
            uploadProgressBlock(uploadProgress);
        }
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        if (success) {
            success(responseObject);
        }
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (failure) {
            failure(error);
        }
    }];
}

// 啟動(dòng)任務(wù)
- (void)resumeTask {
    [self.task resume];
}

// 暫停任務(wù)
- (void)suspendTask {
    [self.task suspend];
}

// 取消任務(wù)
- (void)cancelTask {
    [self.task cancel];
}

// 刪除
- (BOOL)removeDownloadedData:(NSError * _Nullable __autoreleasing * _Nullable)error {
    if (self.downloadway == SPDownloadWayResume) {
        if (SPDownloadLength) {
            
            BOOL isDirectory = NO;
            
            NSFileManager *manager = [NSFileManager defaultManager];
            // 刪除已經(jīng)下載好的文件
            if ([manager fileExistsAtPath:SPFileFullPath isDirectory:&isDirectory] && [manager fileExistsAtPath:SPFileInfoPath isDirectory:&isDirectory]) {
                // 移除
                BOOL removeFileSuccess = [manager removeItemAtPath:SPFileFullPath error:error];
                BOOL removeFileLengthSuccess = [manager removeItemAtPath:SPFileInfoPath error:error];
                if (removeFileSuccess && removeFileLengthSuccess) { // 移除成功

                    [self.task cancel];
                    self.task = nil;
                    return YES;
                } else {
                    NSLog(@"移除文件失敗");
                    return NO;
                }
                
            } else {
                NSLog(@"沒(méi)找到文件路徑");
                return NO;
            }
        } else {
            NSLog(@"沒(méi)有需要?jiǎng)h除的數(shù)據(jù)");
            return NO;
        }
    }
    else {
        if (!_downloading) { // 說(shuō)明沒(méi)有正在下載(下載1)
            BOOL isDirectory = NO;
            
            NSFileManager *manager = [NSFileManager defaultManager];
            // 刪除已經(jīng)下載好的文件
            if ([manager fileExistsAtPath:self.downloadFromZero_filePath isDirectory:&isDirectory]) {
                // 移除
                BOOL removeSuccess = [manager removeItemAtPath:self.downloadFromZero_filePath error:error];
                if (removeSuccess) {
                    [self.task cancel];
                    self.task = nil;
                    return YES;
                } else {
                    NSLog(@"移除失敗");
                    return NO;
                }
                return YES;
            } else {
                NSLog(@"沒(méi)找到文件路徑");
                return NO;
            }
        }
        else { // 正在下載
            NSLog(@"****** ‘SPDownloadWayRestart‘不支持在下載過(guò)程中刪除");
           return NO;
        }
    }
    
}

// 從沙盒中獲取下載的進(jìn)度值
- (CGFloat)storedDownloadProgress {
    _storedDownloadProgress = [self.fileInfoDictionry[@"downloadProgress"] floatValue];
    return _storedDownloadProgress;
}

// 從沙盒中獲取下載是否完畢的標(biāo)識(shí)
- (BOOL)isDownloadCompleted {
    _downloadCompleted = self.fileInfoDictionry[@"downloadCompleted"];
    return _downloadCompleted;
}

// 從沙盒中獲取是否正在下載的標(biāo)識(shí)
- (BOOL)isDownloading {
    _downloading = self.fileInfoDictionry[@"downloading"];
    return _downloading;
}

- (NSOutputStream *)stream {
    if (!_stream) {
        _stream = [NSOutputStream outputStreamToFileAtPath:SPFileFullPath append:YES];
    }
    return _stream;
}

- (NSURLSession *)session {
    if (!_session) {
        _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
    }
    return _session;
}

- (NSURLSessionTask *)task {
    if (!_task) {
        
        if (self.downloadway == SPDownloadWayResume) {
            // 取出文件的總長(zhǎng)度
            NSInteger totalLength = [self.fileInfoDictionry[SPFileName] integerValue];
            if (totalLength && SPDownloadLength == totalLength) {
                NSLog(@"文件已經(jīng)下載完成了");
                return nil;
            }
            // 創(chuàng)建請(qǐng)求
            NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.fileURLString]];
            
            // 設(shè)置請(qǐng)求頭
            // Range : bytes=xxx-xxx
            NSString *range = [NSString stringWithFormat:@"bytes=%zd-", SPDownloadLength];
            [request setValue:range forHTTPHeaderField:@"Range"];
            
            // 創(chuàng)建一個(gè)Data任務(wù)
            _task = [self.session dataTaskWithRequest:request];
        }
        else {
            AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
            
            NSURL *urlpath = [NSURL URLWithString:self.downloadFromZero_UrlString];
            NSURLRequest *request = [NSURLRequest requestWithURL:urlpath];
            
            _task = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
                
                _downloading = YES;
                
                CGFloat progress = 1.0 * downloadProgress.completedUnitCount / downloadProgress.totalUnitCount;
                
                if (self.downloadFromZero_ProgressBlock) {
                    self.downloadFromZero_ProgressBlock(progress);
                }
                
            } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
                
                NSString *cachesPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
                
                NSURL *fileURL = [NSURL fileURLWithPath:cachesPath];
                
                return fileURL;
                
            } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
                
                _downloading = NO;
                self.downloadFromZero_filePath = filePath.path;
                
                if (self.downloadFromZero_completionHandler) {
                    self.downloadFromZero_completionHandler(response,filePath,error);
                }
            }];
        }
    }
    return _task;
        
}

- (NSMutableDictionary *)fileInfoDictionry {
    if (_fileInfoDictionry == nil) {
        //  通過(guò)文件文件路徑初始化字典,第一次取出來(lái)的必為空,因?yàn)榇藭r(shí)還沒(méi)有寫(xiě)進(jìn)沙盒
       _fileInfoDictionry = [NSMutableDictionary dictionaryWithContentsOfFile:SPFileInfoPath];
        if (_fileInfoDictionry == nil) {
            _fileInfoDictionry = [NSMutableDictionary dictionary];
        }
    }
    return _fileInfoDictionry;
}


#pragma mark - <NSURLSessionDataDelegate>
/**
 * 1.接收到響應(yīng)
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
    
    // 打開(kāi)流
    [self.stream open];
    
    // 獲得服務(wù)器這次請(qǐng)求 返回?cái)?shù)據(jù)的總長(zhǎng)度
    self.totalLength = [response.allHeaderFields[@"Content-Length"] integerValue] + SPDownloadLength;
    
    // 存儲(chǔ)總長(zhǎng)度
    self.fileInfoDictionry[SPFileName] = @(self.totalLength);
    [self.fileInfoDictionry writeToFile:SPFileInfoPath atomically:YES];
    
    // 接收這個(gè)請(qǐng)求,允許接收服務(wù)器的數(shù)據(jù)
    completionHandler(NSURLSessionResponseAllow);
}

/**
 * 2.接收到服務(wù)器返回的數(shù)據(jù)(這個(gè)方法可能會(huì)被調(diào)用N次)
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
    
    // 寫(xiě)入數(shù)據(jù),不需要指定寫(xiě)入到哪個(gè)路徑,因?yàn)閟tream在創(chuàng)建的那一刻就紀(jì)錄好存儲(chǔ)路徑
    [self.stream write:data.bytes maxLength:data.length];
    
    // 回調(diào)block
    if (self.downloadProgressBlock) {

        // 獲取進(jìn)度值
        CGFloat progress = 1.0 * SPDownloadLength / self.totalLength;
        //NSLog(@"++++++%f",progress);
        self.downloadProgressBlock(progress);

        self.fileInfoDictionry[@"downloadProgress"] = @(progress);  // 進(jìn)度值
        self.fileInfoDictionry[@"downloading"] = @(YES); // 正在下載的標(biāo)識(shí)
        [self.fileInfoDictionry writeToFile:SPFileInfoPath atomically:YES];

    }
}

/**
 * 3.請(qǐng)求完畢(成功\失敗)
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    
    if (self.completionHandler) {
        self.completionHandler(task.response,[NSURL fileURLWithPath:SPFileFullPath],error);
        // 關(guān)閉流
        [self.stream close];
        self.stream = nil;
        
        // 清除任務(wù)
        self.task = nil;
        
        if (!error) {

            self.fileInfoDictionry[@"downloadCompleted"] = @(YES);  // 下載完成的標(biāo)識(shí)
            self.fileInfoDictionry[@"downloading"] = @(NO); // 正在下載的標(biāo)識(shí)
            [self.fileInfoDictionry writeToFile:SPFileInfoPath atomically:YES];
        } else {
            if ([error.domain isEqualToString:@"NSURLErrorDomain"] && error.code == -999) {
                return;
            }
        }
    }
    
}

@end

#import <CommonCrypto/CommonDigest.h>

@implementation NSString (MD5)

- (NSString *)md5String {
    
    const char *string = self.UTF8String;
    int length = (int)strlen(string);
    unsigned char bytes[CC_MD5_DIGEST_LENGTH];
    CC_MD5(string, length, bytes);
    return [self stringFromBytes:bytes length:CC_MD5_DIGEST_LENGTH];
}

- (NSString *)stringFromBytes:(unsigned char *)bytes length:(NSInteger)length {
    
    NSMutableString *mutableString = @"".mutableCopy;
    for (int i = 0; i < length; i++)
        [mutableString appendFormat:@"%02x", bytes[i]];
    return [NSString stringWithString:mutableString];
}

@end

之所以不用大家普遍使用的URLSessionDownloadTask,是因?yàn)樗鼛缀鯚o(wú)法做到殺死app后繼續(xù)下載,盡管有個(gè)resumeData,也只能實(shí)現(xiàn)后臺(tái)或者暫停后繼續(xù)下載。

github網(wǎng)址:https://github.com/SPStore/SPHTTPSessionManager

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評(píng)論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,559評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,442評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,835評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,581評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,922評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評(píng)論 3 447
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,096評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,639評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,374評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,591評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,789評(píng)論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,196評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,524評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,322評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,554評(píng)論 2 379

推薦閱讀更多精彩內(nèi)容