├── .classpath ├── .gitignore ├── .project ├── .settings ├── org.eclipse.jdt.core.prefs ├── org.eclipse.jdt.ui.prefs ├── org.eclipse.m2e.core.prefs └── org.eclipse.wst.common.project.facet.core.xml ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── cn │ │ └── clxy │ │ └── upload │ │ ├── ApacheHCUploader.java │ │ ├── Config.java │ │ ├── Listener.java │ │ ├── Part.java │ │ ├── UploadFileService.java │ │ └── Uploader.java └── resources │ ├── bigFileUpload.properties │ └── commons-logging.properties └── test └── java └── cn └── clxy └── upload └── UploadFileServiceTest.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | # Package Files # 3 | *.jar 4 | *.war 5 | *.ear 6 | target/ 7 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | BigFileUploadJava 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.common.project.facet.core.builder 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.m2e.core.maven2Builder 20 | 21 | 22 | 23 | 24 | 25 | org.eclipse.jdt.core.javanature 26 | org.eclipse.m2e.core.maven2Nature 27 | org.eclipse.wst.common.project.facet.core.nature 28 | 29 | 30 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.6 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 12 | org.eclipse.jdt.core.compiler.source=1.6 13 | org.eclipse.jdt.core.formatter.align_type_members_on_columns=false 14 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 15 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16 16 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 17 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 18 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 19 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 20 | org.eclipse.jdt.core.formatter.alignment_for_assignment=0 21 | org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 22 | org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 23 | org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 24 | org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 25 | org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 26 | org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 27 | org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 28 | org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 29 | org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 30 | org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 31 | org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 32 | org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 33 | org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 34 | org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 35 | org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 36 | org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 37 | org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 38 | org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 39 | org.eclipse.jdt.core.formatter.blank_lines_after_package=1 40 | org.eclipse.jdt.core.formatter.blank_lines_before_field=0 41 | org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 42 | org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 43 | org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 44 | org.eclipse.jdt.core.formatter.blank_lines_before_method=1 45 | org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 46 | org.eclipse.jdt.core.formatter.blank_lines_before_package=0 47 | org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 48 | org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 49 | org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line 50 | org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line 51 | org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line 52 | org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line 53 | org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line 54 | org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line 55 | org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line 56 | org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line 57 | org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line 58 | org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line 59 | org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line 60 | org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true 61 | org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true 62 | org.eclipse.jdt.core.formatter.comment.format_block_comments=true 63 | org.eclipse.jdt.core.formatter.comment.format_header=false 64 | org.eclipse.jdt.core.formatter.comment.format_html=true 65 | org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true 66 | org.eclipse.jdt.core.formatter.comment.format_line_comments=true 67 | org.eclipse.jdt.core.formatter.comment.format_source_code=true 68 | org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true 69 | org.eclipse.jdt.core.formatter.comment.indent_root_tags=true 70 | org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert 71 | org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert 72 | org.eclipse.jdt.core.formatter.comment.line_length=100 73 | org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true 74 | org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true 75 | org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false 76 | org.eclipse.jdt.core.formatter.compact_else_if=true 77 | org.eclipse.jdt.core.formatter.continuation_indentation=2 78 | org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 79 | org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off 80 | org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on 81 | org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false 82 | org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true 83 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true 84 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true 85 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true 86 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true 87 | org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true 88 | org.eclipse.jdt.core.formatter.indent_empty_lines=false 89 | org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true 90 | org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true 91 | org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true 92 | org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false 93 | org.eclipse.jdt.core.formatter.indentation.size=4 94 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert 95 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert 96 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert 97 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert 98 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert 99 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert 100 | org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert 101 | org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert 102 | org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert 103 | org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert 104 | org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert 105 | org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert 106 | org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert 107 | org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert 108 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert 109 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert 110 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert 111 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert 112 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert 113 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert 114 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert 115 | org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert 116 | org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert 117 | org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert 118 | org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert 119 | org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert 120 | org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert 121 | org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert 122 | org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert 123 | org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert 124 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert 125 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert 126 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert 127 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert 128 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert 129 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert 130 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert 131 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert 132 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert 133 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert 134 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert 135 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert 136 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert 137 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert 138 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert 139 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert 140 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert 141 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert 142 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert 143 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert 144 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert 145 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert 146 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert 147 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert 148 | org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert 149 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert 150 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert 151 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert 152 | org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert 153 | org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert 154 | org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert 155 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert 156 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert 157 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert 158 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert 159 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert 160 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert 161 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert 162 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert 163 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert 164 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert 165 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert 166 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert 167 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert 168 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert 169 | org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert 170 | org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert 171 | org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert 172 | org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert 173 | org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert 174 | org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert 175 | org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert 176 | org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert 177 | org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert 178 | org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert 179 | org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert 180 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert 181 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert 182 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert 183 | org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert 184 | org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert 185 | org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert 186 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert 187 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert 188 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert 189 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert 190 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert 191 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert 192 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert 193 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert 194 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert 195 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert 196 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert 197 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert 198 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert 199 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert 200 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert 201 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert 202 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert 203 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert 204 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert 205 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert 206 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert 207 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert 208 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert 209 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert 210 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert 211 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert 212 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert 213 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert 214 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert 215 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert 216 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert 217 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert 218 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert 219 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert 220 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert 221 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert 222 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert 223 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert 224 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert 225 | org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert 226 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert 227 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert 228 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert 229 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert 230 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert 231 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert 232 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert 233 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert 234 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert 235 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert 236 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert 237 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert 238 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert 239 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert 240 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert 241 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert 242 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert 243 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert 244 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert 245 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert 246 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert 247 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert 248 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert 249 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert 250 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert 251 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert 252 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert 253 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert 254 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert 255 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert 256 | org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert 257 | org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert 258 | org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert 259 | org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert 260 | org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert 261 | org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert 262 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert 263 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert 264 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert 265 | org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert 266 | org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert 267 | org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert 268 | org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert 269 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert 270 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert 271 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert 272 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert 273 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert 274 | org.eclipse.jdt.core.formatter.join_lines_in_comments=true 275 | org.eclipse.jdt.core.formatter.join_wrapped_lines=false 276 | org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false 277 | org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false 278 | org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false 279 | org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false 280 | org.eclipse.jdt.core.formatter.lineSplit=100 281 | org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false 282 | org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false 283 | org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 284 | org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 285 | org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true 286 | org.eclipse.jdt.core.formatter.tabulation.char=tab 287 | org.eclipse.jdt.core.formatter.tabulation.size=4 288 | org.eclipse.jdt.core.formatter.use_on_off_tags=false 289 | org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false 290 | org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true 291 | org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true 292 | org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true 293 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.ui.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | formatter_profile=_Clxy 3 | formatter_settings_version=12 4 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 clxy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BigFileUploadJava 2 | ==================== 3 | 4 | ### [☆ English](#english) ### 5 | ### [☆ 中文](#chinese) ### 6 | 7 | Basics 8 | ----------------------------------- 9 | Upload big file using java. 10 | 11 | ### Process Flow 12 | Basically, read a big file into small parts and upload. When all file parts upload is complete, combine at server. 13 | 14 | #### Client 15 | 16 | 1. Read the big file into several small parts. Considering I/O contention, use just one thread; Considering memory usage, read file part by part into fixed size queue. 17 | 2. Upload every readed file part. Usually multiple threads would be better, but can't too much, default threads count is 5. 18 | 3. After all parts uploaded, notify server to combine. 19 | 4. Can retry the specific parts only if failed to process. 20 | 21 | #### Server 22 | 23 | 1. Save recieved file parts. 24 | 2. Combine all parts by notification. 25 | 26 | #### Others 27 | 28 | - Producer/Consumer pattern. 29 | - Communicate read and upload processes by BlockingQueue. 30 | - Uploading is using Apache HttpComponents currently. There can be other implementations. 31 | - Can be used in the android. Please refer to [BigFileUploadAndroid](https://github.com/clxy/BigFileUploadAndroid)。 32 | 33 | 34 | ### Usage 35 | 36 | #### Configuration 37 | Please refer to [cn.clxy.upload.Config](https://github.com/clxy/BigFileUploadJava/blob/master/src/main/java/cn/clxy/upload/Config.java). 38 | 39 | Please note that the maximum memory usage might be: 40 | ```PART_SIZE * (MAX_UPLOAD + MAX_READ - 1)``` 41 | 42 | #### Upload 43 | UploadFileService service = new UploadFileService(yourFileName); 44 | service.upload(); 45 | 46 | #### Retry failed parts 47 | UploadFileService service = new UploadFileService(yourFileName); 48 | service.retry(1, 2); 49 | 50 | ### Server 51 | Because it is via HTTP, so it can be in any language, such as Java, PHP, Python, etc. 52 | Here is a java example. 53 | 54 | ```Java 55 | ... 56 | try (FileOutputStream dest = new FileOutputStream(destFile, true)) { 57 | 58 | FileChannel dc = dest.getChannel();// the final big file. 59 | for (long i = 0; i < count; i++) { 60 | File partFile = new File(destFileName + "." + i);// every small parts. 61 | if (!partFile.exists()) { 62 | break; 63 | } 64 | try (FileInputStream part = new FileInputStream(partFile)) { 65 | FileChannel pc = part.getChannel(); 66 | pc.transferTo(0, pc.size(), dc);// combine. 67 | } 68 | partFile.delete(); 69 | } 70 | statusCode = OK;// set ok at last. 71 | } catch (Exception e) { 72 | log.error("combine failed.", e); 73 | } 74 | ``` 75 | 76 | * * ** * ** * ** * ** * ** * ** * ** * ** * * 77 | 78 | 79 | 概要 80 | ----------------------------------- 81 | 使用Java上传大文件的实现。 82 | 83 | ### 处理流程 84 | 基本上是将大文件拆成小块,读取,上传。当所有文件块上传完成后,合并。 85 | 86 | #### 客户端 87 | 88 | 1. 读取文件到小的文件块。考虑到I/O竞争只用单线程;考虑到内存消耗采取分批读取。 89 | 2. 将读取的文件块上传。通常多个线程会好些,但是太多又不行,默认用5线程上传。 90 | 3. 所有文件块全部上传后,通知服务器合并。 91 | 4. 如果有部分文件块处理失败,可以重试失败部分。 92 | 93 | #### 服务器 94 | 95 | 1. 收到文件块后直接保存。 96 | 2. 收到通知后合并所有文件块。 97 | 98 | #### 其他 99 | 100 | - 使用生产/消费者模式。 101 | - 读取和上传的通信使用BlockingQueue。 102 | - 目前上传用Apache HttpComponents。可以有其他实现。 103 | - 可以用在Android上。请参考[BigFileUploadAndroid](https://github.com/clxy/BigFileUploadAndroid)。 104 | 105 | 106 | ### 使用 107 | 108 | #### 配置 109 | 请参考 [cn.clxy.upload.Config](https://github.com/clxy/BigFileUploadJava/blob/master/src/main/java/cn/clxy/upload/Config.java). 110 | 111 | 请注意内存的最大使用量可能是: 112 | ```PART_SIZE * (MAX_UPLOAD + MAX_READ - 1)``` 113 | 114 | #### 上传 115 | UploadFileService service = new UploadFileService(yourFileName); 116 | service.upload(); 117 | 118 | #### 重试失败部分 119 | UploadFileService service = new UploadFileService(yourFileName); 120 | service.retry(1, 2); 121 | 122 | ### 服务器 123 | 由于是经由HTTP上传,所以可以是任何语言如Java,PHP,Python等。 124 | 下面是合并文件的Java实例。 125 | 126 | ```Java 127 | ... 128 | try (FileOutputStream dest = new FileOutputStream(destFile, true)) { 129 | 130 | FileChannel dc = dest.getChannel();// 最终的大文件。 131 | for (long i = 0; i < count; i++) { 132 | File partFile = new File(destFileName + "." + i);// 每个文件块。 133 | if (!partFile.exists()) { 134 | break; 135 | } 136 | try (FileInputStream part = new FileInputStream(partFile)) { 137 | FileChannel pc = part.getChannel(); 138 | pc.transferTo(0, pc.size(), dc);// 合并。 139 | } 140 | partFile.delete(); 141 | } 142 | statusCode = OK;// 最终设状态OK。 143 | } catch (Exception e) { 144 | log.error("combine failed.", e); 145 | } 146 | ``` 147 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | BigFileUploadJava 5 | BigFileUploadJava 6 | 0.0.1 7 | Upload big file by java. Using Apache HttpComponents. Can work on Android too. 8 | 9 | 10 | 4.3.6 11 | 12 | 13 | 14 | commons-codec 15 | commons-codec 16 | 1.8 17 | 18 | 19 | org.apache.httpcomponents 20 | httpclient 21 | ${httpcomponents} 22 | compile 23 | 24 | 25 | org.apache.httpcomponents 26 | httpmime 27 | ${httpcomponents} 28 | compile 29 | 30 | 31 | org.apache.httpcomponents 32 | httpclient-cache 33 | ${httpcomponents} 34 | compile 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/java/cn/clxy/upload/ApacheHCUploader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2013 CLXY Studio. 3 | * This content is released under the (Link Goes Here) MIT License. 4 | * http://en.wikipedia.org/wiki/MIT_License 5 | */ 6 | package cn.clxy.upload; 7 | 8 | import java.io.UnsupportedEncodingException; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.Map.Entry; 12 | 13 | import org.apache.commons.logging.Log; 14 | import org.apache.commons.logging.LogFactory; 15 | import org.apache.http.HttpResponse; 16 | import org.apache.http.HttpStatus; 17 | import org.apache.http.client.HttpClient; 18 | import org.apache.http.client.methods.HttpPost; 19 | import org.apache.http.conn.scheme.PlainSocketFactory; 20 | import org.apache.http.conn.scheme.Scheme; 21 | import org.apache.http.conn.scheme.SchemeRegistry; 22 | import org.apache.http.conn.ssl.SSLSocketFactory; 23 | import org.apache.http.entity.mime.MultipartEntity; 24 | import org.apache.http.entity.mime.content.ByteArrayBody; 25 | import org.apache.http.entity.mime.content.ContentBody; 26 | import org.apache.http.entity.mime.content.StringBody; 27 | import org.apache.http.impl.client.DefaultHttpClient; 28 | import org.apache.http.impl.conn.PoolingClientConnectionManager; 29 | import org.apache.http.params.BasicHttpParams; 30 | import org.apache.http.params.HttpConnectionParams; 31 | import org.apache.http.params.HttpParams; 32 | 33 | /** 34 | * Use http client to upload. 35 | * @author clxy 36 | */ 37 | public class ApacheHCUploader implements Uploader { 38 | 39 | private static HttpClient client = createClient(); 40 | private static final Log log = LogFactory.getLog(ApacheHCUploader.class); 41 | 42 | @Override 43 | public void upload(Part part) { 44 | 45 | String partName = part.getName(); 46 | Map params = new HashMap(); 47 | params.put(Config.keyFile, new ByteArrayBody(part.getContent(), partName)); 48 | post(params); 49 | log.debug(partName + " uploaded."); 50 | } 51 | 52 | @Override 53 | public void done(String fileName, long partCount) { 54 | 55 | Map params = new HashMap(); 56 | try { 57 | params.put(Config.keyFileName, new StringBody(fileName)); 58 | params.put(Config.keyPartCount, new StringBody(String.valueOf(partCount))); 59 | } catch (UnsupportedEncodingException e) { 60 | throw new RuntimeException(e); 61 | } 62 | 63 | post(params); 64 | log.debug(fileName + " notification is done."); 65 | } 66 | 67 | private void post(Map params) { 68 | 69 | HttpPost post = new HttpPost(Config.url); 70 | MultipartEntity entity = new MultipartEntity(); 71 | for (Entry e : params.entrySet()) { 72 | entity.addPart(e.getKey(), e.getValue()); 73 | } 74 | post.setEntity(entity); 75 | 76 | try { 77 | HttpResponse response = client.execute(post); 78 | int statusCode = response.getStatusLine().getStatusCode(); 79 | if (statusCode != HttpStatus.SC_OK) { 80 | throw new RuntimeException("Upload failed."); 81 | } 82 | } catch (Exception e) { 83 | post.abort(); 84 | throw new RuntimeException(e); 85 | } finally { 86 | post.releaseConnection(); 87 | } 88 | } 89 | 90 | /** 91 | * The timeout should be adjusted by network condition. 92 | * @return 93 | */ 94 | private static HttpClient createClient() { 95 | 96 | SchemeRegistry schReg = new SchemeRegistry(); 97 | schReg.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory())); 98 | schReg.register(new Scheme("https", 443, SSLSocketFactory.getSocketFactory())); 99 | 100 | PoolingClientConnectionManager ccm = new PoolingClientConnectionManager(schReg); 101 | ccm.setMaxTotal(Config.maxUpload); 102 | 103 | HttpParams params = new BasicHttpParams(); 104 | HttpConnectionParams.setConnectionTimeout(params, 10 * 1000); 105 | HttpConnectionParams.setSoTimeout(params, Config.timeOut); 106 | 107 | return new DefaultHttpClient(ccm, params); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/cn/clxy/upload/Config.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2013 CLXY Studio. 3 | * This content is released under the (Link Goes Here) MIT License. 4 | * http://en.wikipedia.org/wiki/MIT_License 5 | */ 6 | package cn.clxy.upload; 7 | 8 | import java.io.InputStream; 9 | import java.util.Properties; 10 | 11 | public class Config { 12 | 13 | public static String url = "http://192.168.1.99:8080/ssm/common/upload"; 14 | 15 | // Keys used by server. 16 | public static String keyFile = "file"; 17 | public static String keyFileName = "fileName"; 18 | public static String keyPartCount = "partCount"; 19 | 20 | // Upload threads and timeout per thread. Should be adjusted by network condition. 21 | public static int maxUpload = 5; 22 | public static int timeOut = 120 * 1000; 23 | 24 | // The size of part. 25 | public static int partSize = 100 * 1024; 26 | public static int maxRead = 5; 27 | 28 | static { 29 | // load properties 30 | ClassLoader cl = Thread.currentThread().getContextClassLoader(); 31 | try { 32 | InputStream is = cl.getResourceAsStream("bigFileUpload.properties"); 33 | if (is != null) { 34 | Properties p = new Properties(); 35 | p.load(is); 36 | url = p.getProperty("url"); 37 | keyFile = p.getProperty("keyFile"); 38 | keyFileName = p.getProperty("keyFileName"); 39 | keyPartCount = p.getProperty("keyPartCount"); 40 | 41 | String s = p.getProperty("maxUpload"); 42 | maxUpload = Integer.parseInt(s); 43 | s = p.getProperty("timeOut"); 44 | timeOut = Integer.parseInt(s) * 1000; 45 | s = p.getProperty("partSize"); 46 | partSize = Integer.parseInt(s) * 1024; 47 | s = p.getProperty("maxRead"); 48 | maxRead = Integer.parseInt(s); 49 | 50 | } 51 | } catch (Exception e) { 52 | // do nothing. 53 | } 54 | } 55 | 56 | private Config() { 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/cn/clxy/upload/Listener.java: -------------------------------------------------------------------------------- 1 | package cn.clxy.upload; 2 | 3 | public interface Listener { 4 | 5 | void onStart(Object info); 6 | 7 | void onRead(Object info); 8 | 9 | void onUpload(Object info); 10 | 11 | void onPartDone(Object info); 12 | 13 | void onNotify(); 14 | 15 | void onFail(Object info); 16 | 17 | void onSuccess(); 18 | 19 | public static class Default implements Listener { 20 | 21 | @Override 22 | public void onStart(Object info) { 23 | onMessage("Start uploading " + info + " part(s)."); 24 | } 25 | 26 | @Override 27 | public void onRead(Object info) { 28 | onMessage("Reading part " + info + "."); 29 | } 30 | 31 | @Override 32 | public void onUpload(Object info) { 33 | onMessage("Uploading part " + info + "."); 34 | } 35 | 36 | @Override 37 | public void onPartDone(Object info) { 38 | onMessage("Part " + info + " is done."); 39 | } 40 | 41 | @Override 42 | public void onNotify() { 43 | onMessage("Notifying."); 44 | } 45 | 46 | @Override 47 | public void onFail(Object info) { 48 | onMessage(info + " failed."); 49 | } 50 | 51 | @Override 52 | public void onSuccess() { 53 | onMessage("Success."); 54 | } 55 | 56 | protected void onMessage(String msg) { 57 | System.out.println(msg); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/cn/clxy/upload/Part.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2013 CLXY Studio. 3 | * This content is released under the (Link Goes Here) MIT License. 4 | * http://en.wikipedia.org/wiki/MIT_License 5 | */ 6 | package cn.clxy.upload; 7 | 8 | public class Part { 9 | 10 | private byte[] content; 11 | private String name; 12 | public static final Part NULL = new Part(); 13 | 14 | public Part() { 15 | this(null, null); 16 | } 17 | 18 | public Part(String name, byte[] content) { 19 | this.content = content; 20 | this.name = name; 21 | } 22 | 23 | public byte[] getContent() { 24 | return content; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cn/clxy/upload/UploadFileService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2013 CLXY Studio. 3 | * This content is released under the (Link Goes Here) MIT License. 4 | * http://en.wikipedia.org/wiki/MIT_License 5 | */ 6 | package cn.clxy.upload; 7 | 8 | import java.io.File; 9 | import java.io.FileInputStream; 10 | import java.nio.ByteBuffer; 11 | import java.nio.channels.FileChannel; 12 | import java.util.Arrays; 13 | import java.util.Collections; 14 | import java.util.List; 15 | import java.util.concurrent.ArrayBlockingQueue; 16 | import java.util.concurrent.BlockingQueue; 17 | import java.util.concurrent.Callable; 18 | import java.util.concurrent.CompletionService; 19 | import java.util.concurrent.ExecutionException; 20 | import java.util.concurrent.ExecutorCompletionService; 21 | import java.util.concurrent.ExecutorService; 22 | import java.util.concurrent.Executors; 23 | import java.util.concurrent.Future; 24 | 25 | import org.apache.commons.logging.Log; 26 | import org.apache.commons.logging.LogFactory; 27 | 28 | public class UploadFileService { 29 | 30 | private File file; 31 | private BlockingQueue parts; 32 | private List indexes; 33 | 34 | private Listener listener = new Listener.Default(); 35 | private Uploader uploader = new ApacheHCUploader(); 36 | private ExecutorService executor = Executors.newFixedThreadPool(Config.maxUpload); 37 | 38 | private static final Log log = LogFactory.getLog(UploadFileService.class); 39 | 40 | public UploadFileService(String fileName) { 41 | file = new File(fileName); 42 | if (!file.exists() || !file.isFile()) { 43 | throw new RuntimeException("File:" + file + " isn't correct!"); 44 | } 45 | } 46 | 47 | public void upload() { 48 | try { 49 | doUpload(); 50 | } finally { 51 | stop(); 52 | } 53 | } 54 | 55 | public void retry(Integer... array) { 56 | 57 | // sort first. 58 | indexes = Arrays.asList(array); 59 | Collections.sort(indexes); 60 | 61 | try { 62 | doUpload(); 63 | } finally { 64 | stop(); 65 | } 66 | } 67 | 68 | public void stop() { 69 | if (executor != null) { 70 | executor.shutdown(); 71 | } 72 | } 73 | 74 | private void doUpload() { 75 | 76 | listener.onStart(indexes != null ? indexes.size() : getPartCount()); 77 | parts = new ArrayBlockingQueue(Config.maxRead); 78 | CompletionService cs = new ExecutorCompletionService(executor); 79 | 80 | cs.submit(readTask); 81 | 82 | for (int i = 0; i < Config.maxUpload; i++) { 83 | cs.submit(new UploadTask("upload." + i)); 84 | } 85 | 86 | // Wait all done. total count = maxUpload + 1. 87 | for (int i = 0; i <= Config.maxUpload; i++) { 88 | Future future = null; 89 | try { 90 | future = cs.take(); 91 | checkFuture(future); 92 | } catch (InterruptedException e) { 93 | Thread.currentThread().interrupt(); 94 | } 95 | } 96 | 97 | // Notify sever all done. 98 | Future result = executor.submit(notifyTask); 99 | checkFuture(result); 100 | listener.onSuccess(); 101 | } 102 | 103 | private String checkFuture(Future future) { 104 | 105 | String result = null; 106 | try { 107 | result = future.get(); 108 | return result; 109 | } catch (InterruptedException e) { 110 | Thread.currentThread().interrupt(); 111 | return null; 112 | } catch (ExecutionException e) { 113 | listener.onFail(result); 114 | log.error(e.getCause()); 115 | throw new RuntimeException(e.getCause()); 116 | } 117 | } 118 | 119 | protected int getPartCount() { 120 | long length = file.length(); 121 | long count = (length / Config.partSize) + (length % Config.partSize == 0 ? 0 : 1); 122 | return (int) count; 123 | } 124 | 125 | private Callable readTask = new Callable() { 126 | 127 | @Override 128 | public String call() throws Exception { 129 | 130 | FileInputStream fis = null; 131 | String fileName = file.getName(); 132 | int partSize = Config.partSize; 133 | 134 | try { 135 | fis = new FileInputStream(file); 136 | FileChannel fc = fis.getChannel(); 137 | for (int i = 0;; i++) { 138 | ReadStatus status = getReadStatus(i, indexes); 139 | if (status == ReadStatus.stop) { 140 | break; 141 | } 142 | 143 | if (status == ReadStatus.skip) { 144 | fc.position(fc.position() + partSize); 145 | continue; 146 | } 147 | 148 | if (status == ReadStatus.read) { 149 | ByteBuffer bb = ByteBuffer.allocate(partSize); 150 | int bytesRead = fc.read(bb); 151 | if (bytesRead == -1) { 152 | break; 153 | } 154 | byte[] bytes = bb.array(); 155 | if (bytesRead != partSize) {// trim 156 | bytes = Arrays.copyOf(bytes, bytesRead); 157 | } 158 | String partName = createFileName(fileName, i); 159 | listener.onRead(partName); 160 | parts.put(new Part(partName, bytes)); 161 | } 162 | } 163 | } finally { 164 | if (fis != null) { 165 | try { 166 | fis.close(); 167 | } catch (Exception e) { 168 | } 169 | } 170 | parts.put(Part.NULL);// put end signal. 171 | } 172 | 173 | return "read"; 174 | } 175 | 176 | /** 177 | * Create file name of part.
178 | * bigfile.avi = [bigfile.avi.0, bigfile.avi.1, bigfile.avi.2 ...] 179 | * @param fileName 180 | * @param i 181 | * @return 182 | */ 183 | protected String createFileName(String fileName, int i) { 184 | return fileName + "." + i;// start by 0. 185 | // return fileName + (i == 0 ? "" : ("." + i)); 186 | } 187 | 188 | private ReadStatus getReadStatus(int i, List indexes) { 189 | 190 | if (indexes == null || indexes.contains(i)) { 191 | return ReadStatus.read; 192 | } 193 | 194 | if (i > indexes.get(indexes.size() - 1)) { 195 | return ReadStatus.stop; 196 | } 197 | 198 | return ReadStatus.skip; 199 | } 200 | }; 201 | 202 | private static enum ReadStatus { 203 | stop, skip, read 204 | } 205 | 206 | private class UploadTask implements Callable { 207 | 208 | private String name; 209 | 210 | public UploadTask(String name) { 211 | this.name = name; 212 | } 213 | 214 | @Override 215 | public String call() throws Exception { 216 | 217 | while (true) { 218 | 219 | Part part = parts.take(); 220 | if (part == Part.NULL) { 221 | parts.add(Part.NULL);// notify others to stop. 222 | break; 223 | } 224 | 225 | String partName = part.getName(); 226 | listener.onUpload(partName); 227 | uploader.upload(part); 228 | listener.onPartDone(partName); 229 | } 230 | return name; 231 | } 232 | } 233 | 234 | private Callable notifyTask = new Callable() { 235 | @Override 236 | public String call() throws Exception { 237 | uploader.done(file.getName(), getPartCount()); 238 | return "notify"; 239 | } 240 | }; 241 | } 242 | -------------------------------------------------------------------------------- /src/main/java/cn/clxy/upload/Uploader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2013 CLXY Studio. 3 | * This content is released under the (Link Goes Here) MIT License. 4 | * http://en.wikipedia.org/wiki/MIT_License 5 | */ 6 | package cn.clxy.upload; 7 | 8 | public interface Uploader { 9 | 10 | /** 11 | * Upload a part. 12 | * @param part 13 | */ 14 | void upload(Part part); 15 | 16 | /** 17 | * Notify server all uploading is done. 18 | * @param fileName 19 | * @param partCount 20 | */ 21 | void done(String fileName, long partCount); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/bigFileUpload.properties: -------------------------------------------------------------------------------- 1 | url=http://192.168.1.99:8080/ssm/common/upload 2 | 3 | keyFile=file 4 | keyFileName=fileName 5 | keyPartCount=partCount 6 | 7 | maxUpload=5 8 | #unit:second 9 | timeOut=120 10 | 11 | #unit:k 12 | partSize=100 13 | maxRead=5 14 | -------------------------------------------------------------------------------- /src/main/resources/commons-logging.properties: -------------------------------------------------------------------------------- 1 | .level=DEBUG -------------------------------------------------------------------------------- /src/test/java/cn/clxy/upload/UploadFileServiceTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2013 CLXY Studio. 3 | * This content is released under the (Link Goes Here) MIT License. 4 | * http://en.wikipedia.org/wiki/MIT_License 5 | */ 6 | package cn.clxy.upload; 7 | 8 | public class UploadFileServiceTest { 9 | 10 | public static void main(String[] args) { 11 | 12 | UploadFileService service = null; 13 | try { 14 | 15 | service = new UploadFileService("D:\\test.jpg"); 16 | service.upload(); 17 | 18 | service = new UploadFileService("D:\\test.jpg"); 19 | service.retry(1, 2); 20 | } catch (Exception e) { 21 | e.printStackTrace(); 22 | } 23 | } 24 | } 25 | --------------------------------------------------------------------------------